리터럴
- 소스코드 내에서 직접 입력된 값을 리터럴이라고 부른다.
- 정수 리터럴, 실수 리터럴, 문자 리터럴, 논리 리터럴이 있다.
- 정수 리터럴을 저장할 수 있는 타입:
byte
,char
,short
,int
,long
- 정수 리터럴을 저장할 수 있는 타입:
- 사실 리터럴은 상수(constant)와 같은 의미이지만 프로그램에서는 상수를 “값을 한 번 저장하면 변경할 수 없는 변수”로 정의하기 때문에 이와 구분하기 위해 “리터럴”이라는 용어를 사용한다.
Java char 초기화와 String 초기화 구별
1
2
3
4
5
6
7
8
9
// char
char c = null; // 컴파일 에러! (type mismatch)
char c = '\u0000'; // ok!
char c = ''; // 컴파일 에러! (invalid character constant')
char c = ' '; // ok! (유니코드:32)
// String
String str = null; // null 초기화 가능
String str = ""; // 빈문자열 초기화 가능
정수 타입
short 타입
- C언어와(2byte 메모리 체계의 int자료형)의 호환을 위해 사용된다.
c언어에서 Int는 운영체제의 환경에 맞는 크기로 사용된다. 즉 16bit 운영체제에서는 16bit(2byte), 32bit 운영체제에서는 32bit(4byte)를 사용한다. 64bit운영체제부터는32bit로 고정하여 사용한다.
int 타입
- 정수 연산을 하기 위한 기본 타입
- bye 타입 또는 short 타입의 변수를 +연산하면 int 타입으로 변환된 후 연산되고 결과 역시 int타입이 된다. 자바에서 정수 연산을 4byte로 처리하기 때문이다.
long 타입
- 수치가 큰 데이터를 다루는 프로그램에서는 long타입이 필수적으로 사용된다.
- ex) 은행, 우주 관련 프로그램
1
2
//long var = 100000000000 => 컴파일 에러!
long var = 100000000000L
실수 타입
- 정수와 달리 부동소수점(floating-point) 방식으로 저장된다.
1
2
// + m x 10^n
// 부호 가수 지수
자동 타입 변환
- 작은 크기를 가지는 타입이 큰 크기를 가지는 타입에 저장될 때
- 예외 :
char
타입은 음수가 저장될 수 없다. 따라서 음수가 저장될 수 있는 byte타입을 char타입으로 자동 변환시킬 수 없다. - byte(1) < short(2) < int(4) < long(8) < float(4) < double(8)
- 자동 타입 변환 이전의 값은 변환 이후에도 손실 없이 그대로 보존된다. (메모리에서 값이 복사됨)
1
2
3
4
5
6
7
char charValue = '가';
intValue = charValue; // int <- char
System.out.println("가의 유니코드=" + intValue); // 44032
intValue = 200;
double doubleValue = intValue; // double <- int
System.out.println(doubleValue); //200.0
강제 타입 변환(casting)
- 큰 그릇을 작은 그릇 사이즈로 쪼개어서 한 조각만 작은 그릇에 넣는 것과 같다.
- 즉 int 타입을 4개의 byte로 쪼갠 다음, 끝에 있는 1byte만 byte타입 변수에 저장
- 캐스팅 연산자
()
사용 - 값의 손실이 이루어질 수 있다.
강제 타입 변환 주의점
1) 사용자로부터 입력받은 값을 변환할 때 값의 손실이 발생하면 안 된다.
강제 타입 변환 전 변환될 타입의 최소값과 최대값을 벗어나는 지 검사하고, 벗어난다면 타입 변환을 하지 말아야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
// 변환으로 인한 데이터 손실이 발생되지 않게 한다.
public class CheckValueBeforeCasting {
public static void main(String[] args) {
int i = 128;
if( (i<Byte.MIN_VALUE) || (i > Byte.MAX_VALUE) ) {
System.out.println("byte 타입으로 변환할 수 없습니다.");
} else {
byte b = (byte) i;
System.out.println(b);
}
}
}
wrapper 클래스는 최대값과 최소값 상수를 제공하고 있다. (boolean, char은 없음)
ex) Integer.MIN_VALUE, Double.MAX_VALUE
2) 정수 타입을 실수 타입으로 변환할 때 정밀도 손실을 피해야 한다.
float
: 부호(1비트) + 지수(8비트) + 가수(32비트)double
: 부호(1비트) + 지수(11비트) + 가수(52비트)
1
2
3
4
5
6
7
8
int num1 = 123456780;
int num2 = 123456780;
float num3 = num2;
num2 = (int) num3;
int result = num1 - num2;
System.out.println(result); //-4
int 값을 손실 없이 float타입의 값으로 변환할 수 있으려면 가수 23비트로 표현 가능한 값이어야 한다. 123456780은 23비트로 표현할 수 없기 때문에 근사치로 변환된다. 그렇기 때문에 float값을 다시 Int로 변환하면 원래의 Int값을 얻지 못한다.
- 해결책: 모든 Int값을 실수 타입으로 안전하게 변환시키는 double타입을 사용하자!
- int 크기는 32비트이기 때문에 double의 가수 52비트보다는 작기 때문에 어떠한 Int값이라도 안전하게 정밀도 손실 없이 double 타입으로 변환될 수 있다. 그래서 double 값을 원래 Int타입으로 변환해도 손실 없이 복원된다.
연산식에서의 자동 타입 변환
- 연산은 기본적으로 같은 타입의 피연산자 간에만 수행된다.
- 따라서 서로 다른 타입의 피연산자가 있을 경우 두 피연산자 중 크기가 큰 타입으로 자동 변환된 후 연산을 수행한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class OperationsPromotionExample {
public static void main(String[] args){
byte byteValue1 = 10;
byte byteValue2 = 20;
//byte byteValue3 = byteValue1 + byteValue2; //컴파일 에러!
//type mismatch: cannot convert byte to int
int intValue1 = byteValue1 + byteValue2;
System.out.println(intValue1); //30
char charValue1 = 'A';
char charValue2 = 1;
//char charValue3 = charValue1 + charValue2; //컴파일 에러!
int intValue2 = charValue1 + charValue2;
System.out.println("유니코드=" + intValue2);
System.out.println("출력문자=" + (char)intValue2);
int intValue3 = 10;
//int intValue4 = intValue3 / 4.0; //컴파일 에러!
double doubleValue = intValue3 / 4.0;
System.out.println(doubleValue); // 2.5
}
}
왜
byteValue1 = 10
은 괜찮으면서byteValue3 = byteValue1 + byteValue2
는 컴파일 에러가 날까? 이는 리터럴 자체가 4바이트인 int타입이 아니라, 연산의 기본단위가 int이기 때문이다. 연산을 하게 되면 각각의 값은 Int로 자동 타입 변환되고, 따라서 그 결과값도 int타입이 된다. 자동 타입 변환은 작은 크기를 가지는 타입이 큰 크기를 가지는 타입에 저장될 때 발생하는 것이니, 이 상황은 자동타입 변환의 상황이 아니다. 따라서type mismatch
컴파일 오류가 나는 것이다. 정 byte에 넣고 싶다면 캐스팅 연산자로 강제 타입 변환을 해줘서 넣으면 될 것이다.자바는 리터럴 간의 연산은 타입 변환 없이 해당 타입으로 계산한다.