타입을 다른 타입으로 바꾸는 것. 바이트 크기가 작은 자료형에서 큰 자료형으로, 덜 정밀한 자료형에서 더 정밀한 자료형으로 가는 방향은 자동으로 이뤄진다. 값이 손실되지 않기 때문이다.

묵시적 형 변환

작은 쪽에서 큰 쪽으로 대입하면 컴파일러가 알아서 바꿔준다. 묵시적 형 변환이라고 부른다.

byte bNum = 10;
int iNum = bNum;      // 10
 
byte neg = -1;
int iNeg = neg;       // -1
 
int iNum2 = 20;
float fNum = iNum2;   // 4바이트끼리지만 float가 더 정밀하다

1바이트가 4바이트로 늘어날 때 남는 앞자리는 부호 비트 값으로 채워진다. 양수 10은 00001010이라 앞이 0으로 채워져 그대로 10이지만, -1은 11111111이라 앞 3바이트까지 1로 채워져 4바이트 전체가 11111111 11111111 11111111 11111111, 다시 -1이 된다. 어느 쪽이든 값은 그대로 남아 자료 손실이 없다.

명시적 형 변환

반대 방향은 값이 잘릴 수 있어서 개발자가 직접 책임을 진다. (타입)을 앞에 붙여 알고 있으니 그대로 하라고 표시하는 것이 명시적 형 변환이다.

int iNum = 10;
byte bNum = (byte) iNum;      // 10, 1바이트에 들어가니 손실 없음
 
int iNum2 = 1000;
byte bNum2 = (byte) iNum2;    // -24, byte 범위(-128~127)를 벗어나 잘림
 
double dNum = 3.14;
int iNum3 = (int) dNum;       // 3, 소수점이 버려진다

변환 시점이 가르는 결과

형 변환이 언제 일어나는지도 결과를 가른다.

double dNum1 = 1.2;
float fNum2 = 0.9F;
 
int iNum3 = (int) dNum1 + (int) fNum2;   // 1 + 0 = 1
int iNum4 = (int) (dNum1 + fNum2);       // 2.1 을 잘라 2

정수 타입으로서의 char

char는 형 변환을 이해하기에 좋은 예다. 작은따옴표로 묶인 문자 하나를 담고, 2바이트 크기에 유니코드 값을 갖는다. 유니코드표에서 A0041, a0061이고 10진수로 바꾸면 각각 65와 97이다.

문자를 담는다고 하지만 실제로 저장되는 것은 그 문자에 해당하는 정수 값이다. char가 정수 타입인 셈이라 이런 계산이 성립한다.

char c = 'A';
int i = c;                   // 65, 자동 형 변환
char next = (char)(c + 1);   // 'B'

같은 2바이트인 short와는 표현 범위가 다르다. short는 -32,768부터 32,767까지 음수를 포함하고, char는 0부터 65,535까지 0과 양수만 담는다. 부호 비트를 쓰지 않는 만큼 양의 방향으로 두 배 넓다. 그래서 charint로 늘릴 때만은 앞자리가 0으로 채워진다.

'A'가 65라는 것을 알아두면 문자열 문제가 쉬워진다.

c - 'A'    // 알파벳 순서 (0부터)
c - 'a'    // 소문자 순서
c - '0'    // 문자 숫자를 정수로

참고

원본은 byteint로 넓힐 때 “남은 3바이트는 0으로 채워짐”이라고 적었다. byte는 부호 있는 타입이라 부호 확장이 일어난다. 자바 언어 명세는 부호 있는 정수 타입을 넓힐 때 부호 비트를 확장하고, char처럼 부호 없는 타입일 때만 0으로 확장한다고 정한다. byte b = -1; int i = b;의 결과가 0이 아니라 -1인 이유다. JLS 5.1.2

관련

출처