프로그래밍/자바(JAVA)

[자바를 다루는 기술 Vol.1] Session2 변수와 데이터형

aSpring 2021. 4. 26. 08:04
728x90
728x90

21.04.26(월)~4.27(화)

 

※ 몰랐던 내용 위주로 정리 



2장. 자바 프로그래밍을 위한 변수와 데이터형

01. 변수

 

p.48

프로그래밍 언어 : 특성에 따라 변수를 선언하는 방식이 구분됨

1. 정적 타입 지정 언어(Statically typed language) : 자바

    -> 모든 변수를 반드시 정해진 데이터형으로 선언

2. 동적 타입 지정 언어(Dinamic typed language)

    -> 프로그램을 실행할 때 적절한 데이터형이 적용되며 스크립트 언어들이 주로 이 방식 채택

 

변수 == 메모리 영역에 데이터를 저장할 공간(변수가 저장되는 공간 : JVM의 스택 영역)

 

p.49

개발자 : 데이터를 가공해서 변수를 다루는 사람

 

변수명(Variable name) 명명규칙(Naming convention)

- 대소문자 구분(서로 다르게 인식)

- 이름 길이 제한 없음

- 미리 정해진 예약어 사용 불가능

- 숫자로 시작할 수 없음

- 특수문자 : '_'과 '$'만 허용

 

권장 명명 규칙 : for 통일성, 유지 보수, 협업을 위한 규칙 준수

- 변수와 메소드 이름의 첫 글자는 소문자로 선언

- 여러 단어일 때 첫 번째 단어의 첫 글자는 소문자로선언하고 다음 단어의 첫 글자는 대문자로 선언

   ex) int caffeLatte = 1;

- 상수(애플리케이션 안에서 변하지 않게 고정된 데이터) -> 모든 글자를 대문자로 선언

   ex) final int COFFEE_DEFAULT_SIZE = 1;

- 반드시 사용 목적을 내포

 

02. 데이터형의 종류와 사용법

데이터형의 종류

1. 기본형(primitive type) : 자바에서 기본적으로 제공하는 데이터형

- Numeric Type(숫자형) 

   -> Integral Type(정수형) : byte, short, int, long, char

   -> Floating-Point Type(부동소수형) : float, double

- boolean Type

- returnAddress(주소 반환형)

2. 참조형(reference type) : 보통은 클래스를 의미

- reference                  : 문자열/날짜..

   -> class type

   -> interface type

   -> array type

 

정수를 담기 위한 정수형

정수 : 부호가 있는 자연수 (양의 정수 / 0 / 음의 정수

 

자바 : C 혹은 C++과 다르게 unsigned 타입을 제공하지 않음

-> 즉, 숫자형은 무조건 부호를 갖고 있다.

 

정수형

- signed : 부호가 있는

- unsigned : 부호가 없는

 

따라서 자바에서

int num;

signed int num;

과 같다 -> signed는 생략 가능

 

더보기

반대로 부호가 없는 자료형을 선언하려면 unsigned를 작성 해주어야 함

signed int num; == int num;

(-2,417,483,648 ~ 2,417,483,647)

 

unsigned int num;

(0 ~ 4,294,967,297)

 

★ byte, short, int, long 정수형과 Byte, Short, Integer, Long 참조형은 전혀 다른 데이터형!

-- Wrapper 클래스 : Byte, Short, Integer, Long형 ..

- 기본형의 변수를 객체로 사용해야 할 때 사용하는 클래스

- 데이터는 유지시키고 객체로 사용하기 위해 기본형을 감싸는 역할을 함

-> 이 클래스들은 각 데이터형에 대한 최댓값(MIN_VALUE), 최솟값(MAX_VALUE) 속성을 갖고 있음

 

정수형의 크기와 표현 범위

데이터형 크기 기본값 표현 범위
byte 8bit = 1byte 0 -128 ~ 127
short 16bit = 2byte -32,768 ~ 32,767
int 32bit = 4byte -2,147,483,648 ~ 2,147,483,647
long 64bit = 8byte -9,223,372,036,854,775,808 ~ 9,223,372,854,775,807

 

<byte 변수형의 구조>

부호 bit  |-----------------------------Value bits----------------------------------|

0|1 0|1 0|1 0|1 0|1 0|1 0|1 0|1

8bit -> 한 칸은 1bit -> 저장 가능한 데이터 2^8(=256)개

- 첫 번째 bit는 부호(음수, 양수) 정보 저장, 나머지 7개의 bit에 정수 데이터 저장

--> 부호를 제외한 숫자를 표현할 수 있는 영역 : 2^7(=128)

--> 부호와 함께 숫자를 표현할 수 있는 범위 : 음수 -128 ~ -1, 양수 0 ~ 127

- 양수의 최대 절댓값(127)이 항상 음수의 최소 절댓값(128)보다 1이 작은 이유 : 0을 포함하기 때문

 

Overlflow : 컴퓨터 연산 과정에서 한 단어가 표시될 수 있는 최대 정수보다 큰 수가 입력되어 과잉 유출이 되는 것

- 이미 할당한 공간이 모두 채워져 있는 상태에 추가 데이터 입력이 발생한 것을 의미

 

package Session1.com.gilbut.chapter2;
// p.053 각 정수형마다 표현 가능한 최솟값과 최댓값
public class NumberRange {

	public static void main(String[] args) {
		System.out.println("byte range : " + Byte.MIN_VALUE + " ~ " + Byte.MAX_VALUE); // 최솟값, 최댓값을 의미하는 상수
		System.out.println("short range : " + Short.MIN_VALUE + " ~ " + Short.MAX_VALUE);
		System.out.println("int range : " + Integer.MIN_VALUE + " ~ " + Integer.MAX_VALUE);
		System.out.println("long range : " + Long.MIN_VALUE + " ~ " + Long.MAX_VALUE);

		byte vlu = 0;
		// 0부터 300 미만까지 루프 돌림
		for(int i = 0; i < 300; i++) {
			System.out.println(vlu++);
		} // 0~127 까지 출력된 후 오버플로우 발생 -> 나머지는 -128 -127 ... 0 1 2 ... 43까지 출력함
	}
}
byte range : -128 ~ 127
short range : -32768 ~ 32767
int range : -2147483648 ~ 2147483647
long range : -9223372036854775808 ~ 9223372036854775807

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 -128 -127 -126 -125 -124 -123 -122 -121 -120 -119 -118 -117 -116 -115 -114 -113 -112 -111 -110 -109 -108 -107 -106 -105 -104 -103 -102 -101 -100 -99 -98 -97 -96 -95 -94 -93 -92 -91 -90 -89 -88 -87 -86 -85 -84 -83 -82 -81 -80 -79 -78 -77 -76 -75 -74 -73 -72 -71 -70 -69 -68 -67 -66 -65 -64 -63 -62 -61 -60 -59 -58 -57 -56 -55 -54 -53 -52 -51 -50 -49 -48 -47 -46 -45 -44 -43 -42 -41 -40 -39 -38 -37 -36 -35 -34 -33 -32 -31 -30 -29 -28 -27 -26 -25 -24 -23 -22 -21 -20 -19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

 

byte 데이터형 : 네트워크 통신에서 발생하는 데이터값 혹은 시스템의 파일(file)에서 받아들이는 테이터값을 표현하기 위해 주로 사용

 

명시적 선언을 위한 정수 리터럴

byte value1 = 120;
short value2 = 250;
int value3 = 300;

long value4 = 25000L; // 리터럴(literal)
// 또는
long value4 = 25000l; // 리터럴(literal)
// 또는
long value4 = 25000;

25000이란 변수값은 int형도 저장 가능, long도 저장 가능

-> 확실하게 구분하기 위해 25000이란 값을 리터럴 L과 함께 사용 : long형 데이터라고 선언한 것

 

정수형 리터럴 중 접미사 L이 붙으면 long 변수형을 나타니며, L이 없는 경우 int 변수형을 의미

 

정수형 리터럴은 진수법(10, 16, 8, 2진수)에 따라서 표기 방법이 바뀜

진수법 접두어 표기 숫자
10진법 - 0 1 2 3 4 5 6 7 8 9
16진법 0x 또는 0X 0 1 2 3 4 5 6 7 8 9 A B C D E F
8진법 0 0 1 2 3 4 5 6 7
2진법 0b 또는 0B 0 1

- 0X, 0B와 같이 대문자 이용하기 (0은 모두 숫자 0임)

 

package Session1.com.gilbut.chapter2;
// p.056 정수 12를 각 진수법에 따라서 표현하고 콘솔 화면에 출력
public class ScaleExample {

	public static void main(String[] args) {
		int decimal = 12; 		// 10진수
		int hexadecimal = 0XC; 	// 16진수
		int octet = 014; 		// 8진수
		int binary = 0B1100; 	// 2진수
		
		System.out.println(decimal);
		System.out.println(hexadecimal);
		System.out.println(octet);
		System.out.println(binary);
	}
}
12
12
12
12

 

System.out.println();

-> 기본적으로 정수를 1-진법으로 변환하여 출력해줌

 

03 char형이 곧 문자형

char형(Character types, 문자형)

-> 앞에서는 정수형의 일부라고 표현했음..

-> 유니코드 : 세상의 모든 문자를 표현하는 문자 세트(Character set), 16bit로 구성되어 65,536개의 문자 표현 가능

-> Char형 : 유니코드를 표현(16bit == 4byte)

-> 유니코드의 코드는 정수, 유니코드에 맵핑된 것은 문자 : 즉, char형은 유니코드를 의미

 

선언 방법

char firstChar = 'A';
char firstChar = '\u0041';
// 유니코드 사용 시 '\u'를 사용 : 유니코드임을 명시적으로 보여주어야 함

char형 리터럴 문자 표현 : 홑따옴표(''), 유니코드 사용 시 '\u'

   cf) 문자열 리터럴 : 쌍따옴표("")

 

자바 특수문자(escape sequence)

특수 문자 특수 자 표기법 유니코드
backspace(백스페이스) \b \u0008
tab \t \t0009
line feed(개행문자) = LF
- 커서를 다음 행으로 옮기는 기능
\n \u000a
carriage return(복귀문자) = CR
- 커서를 행의 가장 왼쪽에 위치시키는 역할
\r \u000d
double quote(쌍따옴표) \" \u0022
single quote(홑따옴표) \' \u0027
backslash(역슬래시) \\ \u005c

 

04 부동 소수형 이해하기

float -> 32bit = 4byte -> 십진법으로 6~7개의 유효 숫자 표현

- 목적 : single precision -> 단순 정확도를 위한 것

double -> 64bit = 8byte -> 십진법으로 15개의 유효 숫자 표현

- 목적 : double precision -> 두 배의 정확도를 위한 것

 

double형이 float 형보다 표현 범위가 넓어 더 정환가게 데이터 표현 가능

But, float형을 사용하면 보다 빠른 연산 결과 를 얻을 수 있음

 

보통 int를 제외한 나머지 변수형들은 매우 높은 값까지 저장 가능 -> int의 유효 범위 정도만 알면 됨

 

부동 소수형 리터럴

변수형 리터럴
float형 점미사 F 또는 f float price = 2.99F
double형 접미사 D 또는 d double pi = 3.1415926535897932384D;
10진수의 밑수 E 또는 e double tax = 0.0299E1;

-> long형의 리터럴과 마찬가지로 코드의 가독성을 높이기 위해 접미사는 대문자로 표기하는 것을 추천

 

package Session1.com.gilbut.chapter2;
// p.060
public class FloatPointNumber {

	public static void main(String[] args) {
		char TAB_CHAR = '\t';
		
		float price = 2.99f;
		double pi = 3.1415926535897d;
		double tax = 0.299e1;
		
		System.out.println("Variable price" + TAB_CHAR + ": " + price);
		System.out.println("Variable pi" + TAB_CHAR + ": " + pi);
		System.out.println("Variable tax" + TAB_CHAR + ": " + tax);
		
		float maxFloatValue = Float.MAX_VALUE;
		float minFloatValue = Float.MIN_VALUE;
		System.out.println("Overflow" + TAB_CHAR + ": " + maxFloatValue * 10);
		System.out.println("Underflow" + TAB_CHAR + ": " + minFloatValue / 100);
	}
}
Variable price : 2.99
Variable pi : 3.1415926535897
Variable tax : 2.99
Overflow : Infinity
Underflow : 0.0

 

float형이 표현할 수 있는 최댓값 초과(Overflow) : Infinity

float형이 표현할 수 있는 최솟값을 초과(Underflow) : 0.0

 

05 불리언형과 참조형 변수

Boolean : true or false 값을 가지는 데이터형(0, 1의 정수 직접 저장X, 리터럴 사용해 저장)

- 1bit의 데이터 크기 -> 오직 두 가지 값만 가질 수 있음 -> 흑백 노릴를 사용하는 로직에서 많이 사용

 

참조형 변수(Reference type)

참조 변수형 == 클래스 -> 이 클래스가 인스턴스화 되어 생성된 객체 : 참조형 변수

- String, Date 클래스

(기본형을 제외하면 대부분이 클래스)

 

보통 참조형 : 첫 글자가 대문자(String, Long) -> 모든 클래스의 첫 글자는 대문자로 시작

기본형 : 첫 글자가 소문자(long, int)

 

package Session1.com.gilbut.chapter2;

import java.util.Calendar;
import java.util.Date;

// p.062 참조형 변수 예제
public class ReferenceExample {

	public static void main(String[] args) {
		// 참조 변수형 -> 클래스
		String lastName = "Kim";
		String firstName = new String("Benjamin");

		Date endDate = new Date();
		Date nowDate = Calendar.getInstance().getTime();
		
		System.out.println("My full name is " + firstName + " " + lastName);
		System.out.println(endDate);
		System.out.println(nowDate);
	}
}
My full name is Benjamin Kim
Tue Apr 27 06:28:27 KST 2021
Tue Apr 27 06:28:27 KST 2021

 

06 형 변환(Type casting)

변수형을 다른 변수형으로 바꾸는 작업

- 형 변환 연산자 사용 ex (float)

- 주의 : 값 손실, 형 변환 에러

- boolean형(숫자형X, 논리형) 제외하면 모두 형 변환 가능

- 메모리 크기가 더 큰 형으로 변환할 경우 : 묵시적 형 변환 -> 형 변환 연산자를 사용하지 않아도 자동 형 변환

- 반대의 경우 명시적 형 변환 -> 형 변환 연산자 표현

- 보통 기본형 변수 사이 또는 참조형 변수 사이에서만 사용

-> 드물게 참조형 변수에 담긴 데이터를 기본형 형수에 저장하거나 기본형 변수에 담긴 데이터를 참조형 변수에 저장할 수 있음 -> 참조형 변수의 valueOf() 메소드와 같은 형 변환 메소드를 사용해 처리

 

07 JVM에 저장된 데이터 위치 확인

- Runtime Data Area에 데이터가 저장되고 사용이 끝난 데이터는 소멸된다

- 변수 선언 -> JVM의 메모리 영역인 Heap에 저장

- Heap : 참조형이 저장됨

- Stack : 기본형이 저장됨

 

package Session1.com.gilbut.chapter2;
// p.066
public class VariableHashcode {

	public static void main(String[] args) {
		long varLong1 = 32L;
		long varLong2 = 32L;
		int varInt1 = 32;
		System.out.println("varLong1 : " + System.identityHashCode(varLong1));
		System.out.println("varLong2 : " + System.identityHashCode(varLong2));
		System.out.println("varInt1 : " + System.identityHashCode(varInt1));
		
		int varInt2 = (int) varLong2;
		long varLong3 = (long) varInt1;
		System.out.println("varInt2  : " + System.identityHashCode(varInt2));
		System.out.println("varLong3 : " + System.identityHashCode(varLong3));
		
		String str1 = String.valueOf(varLong1);
		String str2 = String.valueOf(varInt1);
		String str3 = String.valueOf(varLong1);
		System.out.println("str1 : " + System.identityHashCode(str1));
		System.out.println("str2 : " + System.identityHashCode(str2));
		System.out.println("str3 : " + System.identityHashCode(str3));
		
		/* System.identifyHashCode() 메소드 : JVM 메모리 영역에 저장된 변수의 위치를 반환 -> 해시 코드(Hash Code) : JVM 메모리의 주소명(실제 주소X) */
	}

}
varLong1 : 1130478920
varLong2 : 1130478920
varInt1 : 1982791261
varInt2 : 1982791261
varLong3 : 1130478920
str1 : 1562557367
str2 : 1101288798
str3 : 942731712

 

해시 코드가 같다 -> 두 변수는 JVM 메모리의 같은 주소에 있는 데이터를 참조하고 있다

- String은 저장된 값이 동일해도 해시 코드는 서로 다름

-> String.valueOf() 메소드를 사용해 매번 새로운 데이터를 생성하기 때문

 

해시 코드를 알아낸다고 해도 우리는 변숫값의 정확한 메모리 주소는 알 수 없음

- 자바에서 생성한 데이터 : JVM Runtime Data 영역에 저장 -> 우리는 그 메모리의 고유 관리번호인 해시 코드만 알 수 있음

- 해시 코드값 : 항상 바뀜, 코드를 다시 실행하면 값이 바뀌어 있을 것 -> JVM이 초기화되면 해시 코드의 값도 바뀜

--> JVM 메모리 영역(힙 영역) 어느 곳이든 데이터가 생길 수 있으며, 그 위치는 개발자가 직접 정할 수 없기 때문

 

[null 키워드로 메모리를 효율적으로 관리]

기본형 변수 - 변수값을 설정하지 X면 그 변수형에 따라 기본값이 존재

ex) int형 : 0, boolean형 : false

 

참조형 변수 - 기본값이 존재하지 않음

-> 값이 없는 상태로 변수 이름만 가지고 있음 -> null 값을 갖고 있다

 

지금까지 살펴본 예제 : 모든 변수에 값을 넣어 사용 -> 메모리에 데이터를 새롭게 생성했다 -> 메모리 사용량 증가

 

애플리케이션의 성능을 높이기 위해 항상 힙 영역의 메모리 관리에 신경 쓰면서 코딩해야 함

 

힙 영역에 데이터를 생성하지 않고 변수를 선언하기 위한 방법

String param = null;

-> param이라는 변수 : JVM 메모리에서 참조하는 변수값이 없음

-> 값이 없는 변수라도 param이라는 변수명은 초기화됨 -> param이라는 변수명 사용 가능

-> null로 선언 후 필요에 따라 새로운 문자열 데이터를 넣을 수도 있고, 사용하지 않고 프로그램을 끝낼 수도 있음

 

* 주의

null != 공백(blank, " ")

 

package Session1.com.gilbut.chapter2;
// p.069 null과 blank
public class VariableHashcode2 {

	public static void main(String[] args) {
		String varStr1 = "";
		String varStr2 = null; // 변수 이름만 생성하기 위해 null 값을 대입하는 경우
		
		System.out.println("varStr1 : " + System.identityHashCode(varStr1)); // 405662939
		System.out.println("varStr3 : " + System.identityHashCode(varStr2)); // 0
	}
}
varStr1 : 405662939
varStr3 : 0

null 키워드의 특수성 -> null 키워드로 선언한 변수의 해시 코드는 항상 0

blank("", 빈값)는 문자로 JVM에서 하나의 메모리를 참조하고 있음

===> blank 문자와 null 키워드는 서로 같지 않으며 자바를 다를 때 항상 구분해서 사용!!

 

 


Java의 메모리 : Stack과 Heap ??

2021.04.27 - [프로그래밍/자바(JAVA)] - [메모리 구조] 자바의 메모리 구조

 

[메모리 구조] 자바의 메모리 구조

 

aspring.tistory.com

 

 

728x90
728x90