[Java] 형변환 (Casting)

김용준·2022년 8월 30일
0

Java Basic

목록 보기
8/22

형변환(Casting)이란?

형변환은 리터럴(값)의 타입을 다른 타입으로 변환하는 것이다. 변수(저장공간)의 타입은 변환시키지 않는다.

컴퓨터는 같은 타입 간의 연산만 가능하다. 그래서 다른 타입 간의 연산을 수행해야 할 때는 '형변환'을 통해 타입을 일치시킨다. 형변환에는 수동 형변환(명시적 형변환)과 자동 형변환이 있다.

수동 형변환

수동 형변환은 개발자가 직접 형변환 연산자(자료형)을 이용해 형변환하는 방법이다. 자료형에 변환하고자 하는 자료형을 넣으면 된다.

실수를 형변환하여 정수형 변수에 저장하는 예제이다.

public class Casting {

	public static void main(String[] args) {
		
		double d = 3.14;
		int i = (int)d;
		
		System.out.println(d); // d=3.14
		System.out.println(i); // i=3
	}
}

실수형 d가 정수형으로 변환되어 소수점 부분은 버려진 값이 i에 저장되었다. 형변환 연산이 수행된 값이 i에 저장되는 과정은 다음과 같다.
1. int i = (int)d;
2. int i = (int)3.14;
3. int i = 3;

위 코드에서 알 수 있듯, 형변환 연산자는 피연산자의 값을 지정된 타입으로 변환하고 그 결과를 반환할 뿐이다. 형변환 연산자는 변수의 타입을 바꾸거나 변수에 저장된 리터럴의 타입을 바꾸어 다시 저장하는 것이 아니다. 그저 값을 반환한다. 그래서 피연산자인 d의 값은 형변환 후에도 변화가 없다.

자동 형변환

자동 형변환은 개발자가 형변환 연산자를 생략해도 컴파일러가 자동으로 추가해준다. 변수의 저장범위가 저장하려는 값보다 크면 자동 형변환이 가능하다. 그래서 자동 형변환은 다음 두 가지 규칙에 따라 발생한다.

값손실이 발생하지 않는 쪽으로 형변환

  1. float f = 1009; // 1009앞에 (float)가 생략됨

위 문장에서 우변은 int타입이고 이 값을 저장하려는 변수의 타입은 float이다. 정수형보다 실수형의 저장 범위가 더 넓다. 그래서 우변의 값이 float로 자동 형변환 된다.

  1. byte b = 130; // 에러, 우변이 byte타입의 범위(-128~127)을 벗어남

변수가 저장할 수 있는 값의 범위보다 더 큰 값을 저장하려는 경우, 형변환을 생략하면 에러가 발생한다.

  1. double d = 5*3.5

우변은 정수와 실수의 곱이고, 그 결과를 double타입의 변수 d에 저장한다. 같은 타입간의 연산만 가능하므로 정수인 5를 범위가 더 넓은 타입인 double로 자동 형변환하여 연산한다. 만일 3.5int형으로 변환한다거나 우변의 결과인 17.5int형으로 변환한다면 소수점이 버려지는 '값손실'이 발생할 것이다.

피연산자의 타입이 int보다 작은 타입이면 int로 변환

첫 번째 규칙은 피연산자의 값 손실을 최소화하기 위한 것이고, 두 번째 규칙은 int보다 작은 타입(char, byte, short)의 표현 범위가 좁아서 연산 중 오버플로우가 발생할 수 있기 때문에 존재한다.

아래와 같은 코드를 작성하면 에러가 발생한다.

byte a = 10;		// int형으로 자동 형변환
byte b = 20;		// int형으로 자동 형변환
byte c = a + b; 	// 에러

ab 모두 int형보다 작은 byte형이기 때문에 자동 형변환 두 번째 규칙에 따라 피연산자들을 int형으로 바꾸어 연산했다. 그래서 a+b의 결과도 int형이다. 그러나 4byte인int형의 값을 1byte인 byte형의 c에 저장하려 했기 때문에 에러가 발생하는 것이다.

크기가 작은 자료형의 변수를 큰 자료형의 변수에 저장할 때는 자동으로 형변환되지만, 반대의 경우에는 명시적으로 형변환 연산자를 사용해야한다. 따라서 위의 세번째 코드를 byte c =(byte)(a + b)로 수정해야 에러가 발생하지 않는다.

주의사항

다음과 같은 경우에는 에러가 발생하지는 않지만 의도한 값과 다른 값이 저장될 수 있다.

public class Casting {

	public static void main(String[] args) {
		
		int a = 1_000_000; // 1백만
		int b = 2_000_000; // 2백만
		
		long c = a*b;
		
		System.out.println(c); //a*b = 2조, 그러나 출력은 -1454759936
	}
}

a*b의 결과를 담는 변수c의 타입이 long타입이기 때문에 210122*10^{12} 를 저장하기에 충분하므로 2_000_000_000_000이 출력될 것 같지만 오버플로우가 발생하여 다른 값이 출력된다. 그 이유는 a*b의 결과가 이미 int타입의 값이므로 long타입으로 자동 형변환되어도 값은 변하지 않기 때문이다. 그저 오버플로우된 값이 출력된다.

profile
차선이 모여 최선이 된다.

0개의 댓글