1. 형변환이란?
프로그램을 작성하다 보면 타입 간의 연산뿐만 아니라 다른 타입과의 연산을 해야 할 때가 있는데, 연산을 하기 위해서는 서로 간의 타입을 일치시켜야 하므로 반드시 '형변환'을 해야 한다. 즉, 변수나 리터럴 타입을 다른 타입으로 변환하는 것을 '형변환(Casting)'이라 한다.
2. 형변환의 방법
(타입)피연산자
괄호 안의 타입은 변경하고자 하는 타입을 변환하고자 하는 값의 앞에 괄호 형태로 넣어주면 된다. 이때 사용되는 괄호()는 '캐스트 연산자' 또는 '형변환 연산자'라고 하며, 형변환을 캐스팅(casting))이라고도 한다.
일반적 형변환의 예시
class CastingEx{
public static void main(String[] args){
double d = 75.4;
int score = int(d);
System.out.println("score = " + score);
System.out.println("d = " + d);
}
}
-----
[실행결과]
score = 75
d.75.4 ← 이때 형변환 이후에도 피연산자에는 아무런 변화가 없다.
추가로 알아둬야 할 점은 기본형(primitive type)은 boolean을 제외한 나머지 타입들은 서로 형변환이 가능하다.
3. 정수형 간의 형변환
1) 큰 타입에서 작은 타입으로의 변환
예를 들어 int 타입의 값을 byte 타입으로 변환하는 경우는 크기의 차이만큼 값이 잘려나간다. 그래서 경우에 따라서는 값 손실이 발생할 수 있다.
2) 작은 타입에서 큰 타입으로의 변환
예를 들어 byte의 값을 int 타입의 값으로 변환하는 경우에는 저장공간의 부족으로 값이 손실되는 일은 발생하지 않으므로 값 손실은 발생하지 않는다. 그리고 나머지 빈 공간은 0 또는 1로 채워진다. 다만, 변환하려는 값이 양수가 아닌 음수일 경우에는 빈 공간에는 1로 채워야 한다. 그 이유는 형변환 후에도 부호를 유지할 수 있도록 하기 위해서다.
4. 실수형 간의 형변환
1) 작은 타입(float)에서 큰 타입(double)으로 변환
빈 공간을 0으로 채운다. 이때 float타입의 값을 double 타입으로 변환하는 경우, 지수(E)는 float의 기저인 127을 뺀 후 double의 기저인 1023을 더해 변환하고, 가수(M)는 float의 가수 23자리를 채우고 남은 자리를 0으로 채운다.
2) 큰 타입에서 작은 타입으로 변환
위와 반대로 double의 지수(E)의 기저인 1023을 뺀 후 float의 기저인 127을 더하고, 가수(M)는 double의 가수 52자리 중 23자리만 저장되고 나머지는 버려진다. 단, 한 가지 주의점은 형변환 할 때 가수의 24번째 자리 값이 1이라면 반올림이 발생하여 23번째 자리의 값이 1 증가한다. 마지막으로 float 타입의 범위를 초과하는 값을 float로 형변환하는 경우 앞서 말했듯이 '무한대' 또는 '+-0'을 결과로 얻는다.
5. 정수형과 실수형 간의 형변환
1) 정수형을 실수형으로 변환
정수는 소수점 이하의 값이 없으므로 변환이 간단하다. 그저 정수를 2진수로 변환한 다음 정규화를 거쳐 실수의 저장 형식에 맞게 저장만 하면 된다. 다만 한 가지 주의할 점은 실수형의 정밀도 제한으로 인한 오차가 발생할 수 있다는 것이다.
정수형의 실수형 형변환 오차 발생의 예시
91234567 → (float) → 91234568.0 → (int) → 91234568
91234567 → (double) → 91234567.0 → (int) → 91234567
위와 같이 특정 값을 float타입으로 형변환 했다가 int타입으로 재 형변환 할 경우 int의 최대값은 약 20억으로 최대 10자리의 정밀도를 요구한다. 하지만 float는 10진수로 약 7자리의 정밀도만 제공하므로 int를 float로 변환할 때 정밀도 차이에 의한 오차가 발생할 수 있다. 그래서 10진수로 8자리 이상의 값을 실수형으로 변환할 때는 double로 형변환 해야 오차가 발생하지 않는다.
2) 실수형을 정수형으로 변환
실수형을 정수형으로 변환하면 실수형의 소수점 이하 값은 버려진다. 정수형의 표현 형식으로는 소수점 이하의 값을 표현할 수 없기 때문이다. 예를 들어 float 타입의 살수 9.1234567f를 int 타입으로 형변환 하면 값은 9가 된다. 그렇기 때문에 실수형을 정수형으로 형변환 할 때는 반올림이 발생하지 않는다. 만일 실수의 소수점을 버리고 남은 정수가 정수형의 저장 범위를 초과하는 경우에는 정수의 오버플로우가 발생한 결과를 얻는다.
1.777 → (int) → 1
6. 자동형변환
경우에 따라 편의상의 이유로 형변환을 생략할 수 있는데, 이는 형변환이 이루어지지 않은 것이 아닌 컴파일러가 생략된 형변환을 자동적으로 추가한다.
float f = 1234; //형변환의 생략: float f = (float)1234;와 같다
byte b = 1000; //에러: byte의 범위(-128~127)를 넘는 값을 저장
chat ch = (char)1000; //명시적 형변환: 에러가 발생하지 않는다
--
int i = 3;
double d = 1.0 + i; // double d = 1.0 + (double)i;에서 형변환이 생략
--
double d = 1.0 + i;
>> double d = 1.0 + (double)i;
>> double d = 1.0 + (double)3; //3을 double 타입으로 형변환하면 3.0이 된다
>> double d = 1.0 + 3.0; //double과 double의 덧셈 결과 타입은 double이다
>> double d = 4.0; //double + double = double
그렇다면 컴파일러의 자동 형변환 기준은 무엇일까?
기존 값을 최대한 보존할 수 있는 타입으로 자동 형변환한다.
표현 범위가 좁은 타입에서 넓은 타입으로 형변환 할 때는 값 손실이 없으므로 두 타입중 표현범위가 더 넓은 쪽으로 형변환된다.
※ 형변환 할 때 주의사항
1. boolean을 제외한 나머지 7개의 기본형은 서로 형변환이 가능하다.
2. 기본형과 참조형은 서로 형변환 할 수 없다.
3. 서로 다른 타입의 변수끼리의 연산은 형변환을 하는 것이 원칙이지만 값의 범위가 작은 타입에서 큰 타입으로의 형변환은 생략할 수 있다.
'Java > Basic' 카테고리의 다른 글
조건문(if, switch) (0) | 2021.02.19 |
---|---|
연산자 (0) | 2021.02.18 |
기본형(primitive type) (0) | 2021.02.16 |
화면 출력과 화면 입력 (0) | 2021.02.14 |
변수와 상수 (0) | 2021.02.13 |
댓글