들어가며
우리의 관점에서 1.0과 1은
동일한 값이다.
그러나 자바의 관점에서는
1.0과 1은 전혀 다른 값이다.
이 두값을 표현하고 저장하는
방식이 전혀 다르기 때문이다.
자료형의 변환이 의미하는 것은?
int형 정수의 덧셈 방법과
double형 실수의 덧셈 방법은
다르다.
데이터의 표현 방법에 따라서
덧셈 방법도 달라지기 때문이다.
때문에 다음과 같은 문장이
있다면,
컴파일러는 두 변수 num1과
num2의 자료형이 동일할
것을 기대한다.
자료형이 다른 두 값을 대상으로는
덧셈을 진행할 수 없다.
System.out.println(num1 + num2);
그런데 예상과 달리 다음과
같이 선언되어 있다면,
이대로는 덧셈을 할 수 없어서
두 변수의 자료형을 하나로
일치시키는 과정을 거쳐야 한다.
int num1 = 50;
long num2 = 3147483647L;
System.out.println(num1 + num2);
// num1과 num2의 자료형이 다르다.
이 상황에서는 int형 변수에
담긴 값을
long형으로 변환해야 데이터의
손실이 없이 연산이 가능하다.
따라서 다음의 과정을 거쳐서
연산을 마무리한다.
- 변수 num1에 저장된 값을 long형으로 변환하여 메모리에 임시 저장한다.
- 이어서 이 변환된 값과 num1에 저장된 값을 대상으로 덧셈을 진행한다.
이러한 일련의 과정을 가리켜
'자료형 변환',
줄여서 '형 변환'이라고 한다.
자동 형 변환(Implicit Conversion)
앞서 보인 형 변환의 예를 가리켜
'자동 형 변환'이라고 한다.
프로그래머가 명시한 형 변환이
아니라,
필요한 상황에서 자동으로
형 변환이 일어났기 때문이다.
이렇듯 형 변환이 필요한
상황에서는
다음 두 규칙에 근거하여
자동으로 형 변환이 일어난다.
- 규칙 1. 자료형의 크기가 큰 방향으로 형 변환이 일어난다.
- 규칙 2. 자료형의 크기에 상관없이 정수 자료형보다 실수 자료형을 우선한다.
이 두 규칙을 토대로 자동 형
변환이 일어나는 방향을
화살표로 표시하면 다음과
같다.
위의 그림에서 보이듯이
int형 데이터는 필요시,
long, float, double형 데이터로
자동 형 변환된다.
그리고 모든 데이터는 필요시
double형 데이터로 자동 형
변환 된다.
예를 들면 다음과 같다.
- 자동 형 변환의 예 1
double num1 = 30;
// int형 정수 30은 double형으로 자동 형 변환
- 자동 형 변환의 예 2
System.out.println(59L + 34.5);
// long형 정수 59L은 double형으로 자동 형 변환
참고로 형 변환의 규칙에서
크기에 상관 없이,
실수형이 정수형에 우선하는
이유는
정수형에 비해 실수형이
값의 표현 범위가
더 넓기 때문이다.
즉 정수형 데이터를 실수형으로
변환하면
데이터의 손실은 발생하지
않는다.
비록 오차는 존재하겠지만
말이다.
명시적 형변환
자동 형 변환이 진행되지 않는
상황에서도
필요하다면 '명시적 형 변환'을
통해서
형 변환이 이뤄지도록 문장을
구성할 수 있다.
방법은 다음과 같다.
double pi = 3.141592;
int wholeNumber = (int)pi;
// pi의 값을 int형으로 명시적 형 변환
위의 예에서 변수 pi의 값을
int형으로 형 변환하였다.
형 변환 규칙에는 어긋나지만
컴파일 오류 없이 변환이 이뤄진다.
하지만 이렇듯 실수형 데이터를
정수형으로 변환 시
소수점 이하의 값이 탈락된다.
즉 변수 wholeNumber에 저장되는
값은 정수 3이다.
한가지 예를 더 보이겠다.
long num1 = 3000000007L;
int num2 = (int)num1;
// num의 값을 int로 명시적 형 변환
위의 문장에서는 long형에서
int형으로의
명시적 형 변환을 요구하고 있다.
이렇듯 크기가 큰 정수 자료형에서
작은 크기의 정수 자료형으로
형 변환을 진행하는 경우에는
상위 바이트가 잘려나간다.
즉 num1의 상위 4바이트를
제외한 나머지 바이트만
num2에 저장된다.
따라서 잘려나가는 상위
4바이트에
유효한 데이터가 존재하는
경우에는,
알 수 없는 값으로 변환이
되므로 주의가 필요하다.
그렇다면 언제 명시적 형
변환을 해야 하는가?
여러 상황이 존재하지만
다음 코드를 통해서
한가지 사례를 보이겠다.
이는 정상적으로 컴파일이
될 것 같은 코드이다.
그러나 컴파일 오류가 발생한다.
short num1 = 1;
short num2 = 2;
short num3 = num1 + num2; // 컴파일 오류 발생
오류의 원인은 이렇다.
덧셈 연산을 위해서 num1과
num2에 저장된 값이
int형으로 변환되어 메모리
공간에 임시 저장된다.
그리고 덧셈이 이뤄져 그 결과가
만들어진다.
그런데 그 결과는 int형이므로
대입의 과정에서 문제가
발생한다.
따라서 위의 코드가 컴파일
되기 위해서는
다음과 같이 명시적 형 변환을
해야 한다.
short num3 = (short)(num1 + num2);
위의 문장에서 소괄호가
두 번 등장하였다.
하나는 num1과 num2의
덧셈 연산을 묶을 목적으로,
다른 하나는 형 변환을
목적으로 등장하였다.
이 중에서 형 변환에 사용된
소괄호는
다음 Chapter에서 설명하는
'연산자'로 분류한다.
반면에 묶거나 구분하는
목적으로 사용이 되는 소괄호는
'구분자'라고 하여, 그 성격이
연산자와 다르다.
참고 및 출처
|