큰 범위에서 작은 범위 대입은 명시적 형변환이 필요하다.
double
은 실수를 표현할 수 있다. 따라서 1.5
가 가능하다. 그런데 int
는 실수를 표현할 수 없다. 이 경우 double
→ int
로 대입하면 어떻게 될까?
package casting;
public class Casting2 {
public static void main(String[] args) {
double doubleValue = 1.5;
int intValue = 0;
// intValue = doubleValue; // 컴파일 오류 발생
intValue = (int) doubleValue; // 형변환
System.out.println("intValue = " + intValue); // intValue = 1
System.out.println("doubleValue = " + doubleValue); // doubleValue = 1.5
}
}
다음 코드의 앞부분에 있는 주석을 풀면(제거하면) 컴파일 오류가 발생한다.
intValue = doubleValue; // 컴파일 오류 발생
java: incompatible types: possible lossy conversion from double to int
// java: 호환되지 않는 유형: double에서 int로의 가능한 손실 변환
int
형은 double
형 보다 숫자의 표현 범위가 작다. 그리고 실수를 표현할 수도 없다. 따라서 이 경우 숫자가 손실되는 문제가 발생할 수 있다.
이런 문제는 매우 큰 버그를 유발할 수 있다. 예를 들어서 은행 프로그램이 고객에게 은행 이자를 계산해서 입금해야 하는데 만약 이런 코드가 아무런 오류 없이 수행된다면 끔찍한 문제를 만들 수 있다. 그래서 자바는 이런 경우 컴파일 오류를 발생시킨다.
하지만 만약 이런 위험을 개발자가 직접 감수하고도 값을 대입하고 싶다면 데이터 타입을 강제로 변경할 수 있다.
예를 들어서 대략적인 결과를 보고 싶은데, 이때 소수점을 버리고 정수로만 보고 싶을 수 있다.
형변환은 다음과 같이 변경하고 싶은 데이터 타입을 (int)
와 같이 괄호를 사용해서 명시적으로 입력하면 된다.
intValue = (int) doubleValue; // 형변환
이것을 형(타입)을 바꾼다고 해서 형변환이라 한다. 영어로는 캐스팅이라 한다. 그리고 개발자가 직접 형변환 코드를 입력한다고 해서 명시적 형변환이라 한다.
// doubleValue = 1.5
intValue = (int) doubleValue;
intValue = (int) 1.5; // doubleValue에 있는 값을 읽는다.
intValue = 1; // (int)로 형변환 한다. intValue에 int형인 숫자 1을 대입한다.
형변환 후 출력해보면 숫자 1
이 출력되는 것을 확인할 수 있다.
참고로 형변환을 한다고 해서 doubleValue
자체의 타입이 변경되거나 그 안에 있는 값이 변경되는 것은 아니다. doubleValue
에서 읽은 값을 형변환 하는 것이다. doubleValue
안에 들어있는 값은 1.5
로 그대로 유지된다. 참고로 변수의 값은 대입연산자(=
)를 사용해서 직접 대입할 때만 변경된다.
형변환을 할 때 만약 작은 숫자가 표현할 수 있는 범위를 넘어서면 어떻게 될까?
package casting;
public class Casting3 {
public static void main(String[] args) {
long maxIntValue = 2147483647; // int 최고값
long maxIntOver = 2147483648L; // int 최고값 + 1(초과)
int intValue = 0;
intValue = (int) maxIntValue; // 형변환
System.out.println("maxIntValue casting = " + intValue); // maxIntValue casting = 2147483647
intValue = (int) maxIntOver; // 형변환
System.out.println("maxIntOver casting = " + intValue); // maxIntOver casting = -2147483648
}
}
long maxIntValue = 2147483647
를 보면 int
로 표현할 수 있는 가장 큰 숫자인 2147483647
을 입력했다. 이 경우 int
로 표현할 수 있는 범위에 포함되기 때문에 다음과 같이 long
→ int
로 형변환을 해도 아무런 문제가 없다.
intValue = (int) maxIntValue; // 형변환
어떻게 수행되는지 확인해보자.
maxIntValue = 2147483647; // int 최고값
intValue = (int) maxIntValue; // 변수 값 읽기
intValue = (int) 2147483647L; // 형변환
intValue = 2147483647;
다음으로 long maxIntOver = 2147483648L
를 보면 int
로 표현할 수 있는 가장 큰 숫자인 2147483647
보다 1큰 숫자를 입력했다. 이 숫자는 리터럴은 int
범위를 넘어가기 때문에 마지막에 L
을 붙여서 long
형을 사용해야 한다.
이 경우 int
로 표현할 수 있는 범위를 넘기 때문에 다음과 같이 long
→ int
로 형변환 하면 문제가 발생한다.
intValue = (int) maxIntOver; // 형변환
어떻게 수행되는지 확인해보자.
maxIntOver = 2147483648L; // int 최고값 + 1
intValue = (int) maxIntOver; // 변수 값 읽기
intValue = (int) 2147483648L; // 형변환 시도
intValue = -2147483648;
-2147483648
이라는 전혀 다른 숫자가 보인다. int
형은 2147483648L
를 표현할 수 있는 방법이 없다. 이렇게 기존 범위를 초과해서 표현하게 되면 전혀 다른 숫자가 표현되는데, 이런 현상을 오버플로우라 한다.-2147483648
숫자는 int
의 가장 작은 숫자이다.intValue
)의 타입을 int
→ long
으로 변경해서 사이즈를 늘리면 오버플로우 문제가 해결된다.