타입 변환이란 하나의 데이터 타입을 다른 데이터 타입으로 변환하는 과정을 말한다. 예를 들어, byte 타입을 int 타입으로 변환하거나 그 반대로 변환하는 것이 여기에 해당한다. 자바에서는 자동(묵시적) 타입 변환과 강제(명시적) 타입 변환이라는 두 가지 주요 타입 변환 방식이 존재한다.
자바에서 타입 변환은 필수적인 개념이다. 자동 변환과 강제 변환의 차이를 이해하고, 변환 과정에서 발생할 수 있는 데이터 손실에 주의해야 한다. 특히, 실수에서 정수로의 변환이나 큰 타입에서 작은 타입으로의 변환에서는 항상 캐스팅 연산자를 사용해야 하며, 데이터의 손실 가능성을 염두에 두어야 한다.
[자동(묵시적) 타입 변환 (Implicit Type Conversion)]
자동 타입 변환은 자바 컴파일러가 프로그램 실행 중에 자동으로 수행하는 타입 변환을 말한다. 주로 더 작은 크기의 타입을 더 큰 크기의 타입에 대입할 때 발생한다. 이 경우 데이터의 손실이 없거나 최소화될 수 있는 방향으로 변환이 이루어진다.
1. 타입 크기와 범위
- byte는 1바이트, int는 4바이트, long은 8바이트를 사용한다.
- float는 4바이트 크기를 가지지만, 소수점을 표현할 수 있어 int와 long보다 더 큰 범위의 값을 표현할 수 있다.
byte byteValue = 10;
int intValue = byteValue; // 자동 타입 변환
int intValue1 = 200;
double doubleValue = intValue1; // 자동으로 200.0으로 변환
int intValue2 = 3.14; // 오류: int형 범위보다 더 큰 double형
byte byteValue = 200; // 오류: byte는 -128 ~ 127 범위만 허용
작은 크기의 byte 타입을 큰 크기의 int 타입으로 변환할 때, 데이터 손실 없이 자동으로 변환된다. 또한, int 타입을 double로 변환하면 소수점이 추가된 값으로 변환된다.
그러나 타입의 크기 차이로 인해 자동 변환이 불가능한 경우도 있는데, 변수가 표현할 수 있는 범위보다 더 큰 값을 대입하게 되면 데이터 손실이 발생한다. 따라서 이 대입 연산에 대해서는 컴파일 오류가 발생한다.
2. 문자와 정수 간의 자동 변환
char charValue = 'A';
int intValue = charValue; // 65가 저장됨 (유니코드 값)
byte byteValue = 65;
char charValue = byteValue; // 컴파일 오류
char charValue = (char) byteValue; // 강제 타입 변환 필요
int intValue = -10;
char charValue = (char) intValue; // 양수 범위 내의 값으로 변환됨
char 타입은 2바이트 크기를 가지며, 유니코드 값을 저장한다. char 타입을 int로 변환할 때는 해당 유니코드 값이 저장된다. int는 변환 시 0 ~ 65535 범위로 맞추어 변환되므로, char로 변환할 수 있다. 음수의 경우에도 char의 유효 범위에 맞는 값으로 변환되기 때문에 자동 변환이 가능하다.
하지만 byte의 경우 -128 ~ 127 범위의 값을 저장할 수 있는데, 이 범위에는 음수 값이 포함될 수 있으며, 크기도 char보다 작기 때문에 자바에서는 자동 변환이 불가능하다. 자바는 자동 변환이 발생할 때 데이터 손실이 없고, 의미적으로 올바른 변환만 허용하는데, byte에서 char로 변환할 경우 데이터 손실이 발생할 가능성이 있기 때문에 자동 변환을 지원하지 않는다.
자동(묵시적) 타입 변환 예시 코드
public class Example{
public static void main(String[] args){
byte byteVAlue = 10;
int intValue = byteValue; // int <- byte
System.out.println(intValue); // 10
char charValue = '가';
intValue = charValue; // int <- char
System.out.println("가의 유니코드 = " + intValue); // 가의 유니코드 = 44032
intValue = 500;
long longValue = intValue; // long <- int
System.out.println(longValue); // 500
intValue = 200;
double doubleValue = intValue; // double <- int
System.out.println(doubleValue); // 200.0
}
}
[강제(명시적) 타입 변환 (Explicit Type Conversion)]
큰 크기의 데이터 타입을 작은 크기의 데이터 타입으로 변환하려면 강제 타입 변환을 사용해야 한다. 이를 캐스팅(casting) 이라고 하며, 캐스팅 연산자를 이용해 원하는 타입으로 변환할 수 있다.
int intValue = 10;
byte byteValue = (byte) intValue; // 강제 타입 변환
long longValue = 300;
int intValue = (int) longValue; // 300이 그대로 저장됨
int 타입은 4바이트이지만, byte는 1바이트만을 저장할 수 있습니다. 따라서 강제로 4바이트 중 끝의 1바이트만 저장하게 된다
또한, long 타입을 int로 변환할 때도 강제 변환이 필요합니다. 이 경우 long 값이 int의 범위 내에 있으므로 값이 그대로 유지됩니다.
1. 실수에서 정수로의 변환
double doubleValue = 3.14;
int intValue = (int) doubleValue; // 3으로 변환됨 (소수점 이하 버림)
long longValue = 9876543210L;
int intValue = (int) longValue; // 데이터 손실 발생
실수 타입(float, double)에서 정수 타입으로 변환할 때도 강제 타입 변환이 필요하다. 이 과정에서 소수점 이하의 값은 손실된다.
강제 타입 변환을 사용할 때는 데이터 손실의 위험이 있다. 큰 값을 작은 타입으로 변환하면 일부 데이터가 손실될 수 있으므로 신중하게 사용해야 한다.
강제(명시적) 타입 변환 예시 코드
public class Example{
public static voiud main(String[] args){
int intValue = 44032;
char charValue = (char) intValue;
System.out.println(charValue); // 가
long longValue = 500;
intValue = (int) longValue;
System.out.println(intValue); // 500
double doubleValue = 3.14;
intValue = (int) doubleValue;
System.out.println(intValue); // 3
}
}
2. 강제 타입 변환 주의점
사용자로부터 입력받은 값을 변환할 때 값의 손실이 발생하면 안된다는 것이다. 강제 타입 변환을 하기 전에 우선 안전하게 값이 보존될 수 있는지 검사하는 것이 좋다. 자바는 코드에서 데이터 값을 검사하기 위한 모든 기본 타입에 대해 최대값(max)과 최소값(min)을 다음과 같이 상수로 제공하고 있다.(boolean과 char타입 제외)
기본 타입 | 최대값 상수 | 최소값 상수 |
byte | Byte.MAX_VALUE | Byte.MIN_VALUE |
short | Short.MAX_VALUE | Short.MIN_VALUE |
int | Integer.MAX_VALUE | Integer.MIN_VALUE |
long | Long.MAX_VALUE | Long.MIN_VALUE |
float | Float.MAX_VALUE | Float.MIN_VALUE |
double | Double.MAX_VALUE | Double.MIN_VALUE |
이를 이용해 타입 변환 시 최소값과 최대값을 벗어나는지 검사하고, 만약 벗어난다면 타입 변환을 하지 않도록 할 수 있다.
public class Example{
public static void main(String[] args){
int i=128;
if((i<Byte.MIN_VALUE) || (i>Byte.MAX_VALUE}){
System.out.println("byte 타입으로 변환할 수 없습니다.");
}else{
byte b = (byte) i;
System.out.println(b);
}
}
}
/*
실행 결과 : byte 타입으로 변활할 수 없습니다.
*/
또 다른 주의점은 정수 타입을 실수 타입으로 변환할 때 정밀도 손실을 피해야 한다.
public class Example{
public static void main(String[] args){
imt num1 = 123456780;
int num2 = 123456780;
//수정 전
float num3 = num2;
num2 = (int)num3;
int reault = num1 - num2;
System.out.println(result); // -4
//수정 후
double num3 = num2;
num2 = (int)num3;
int reault = num1 - num2;
System.out.println(result); // 0
}
}
첫번째 실행 결과를 보면 0이 나오지 않는데 이러한 결과가 나온 이유는 int값을 float타입으로 자동 변환하면서 문제가 발생했기 때문이다. float타입은 다음과 같이 비트 수가 할당되어 있다
float: 부호(1비트) + 지수(8비트) + 가수(23비트)
int 값을 손실 없이 float타입의 값으로 변환할 수 있으려면 가수 23비트로 표현 가능한 값이어야 한다. 위의 값은 23비트로 표현할 수 없기 때문에 근사치로 변환되어 정밀도 손실이 발생한다. 이 때는 모든 int 값을 실수 타입으로 안전하게 변환시키는 double타입을 사용하는 것이다.
double: 부호(1비트) + 지수(11비트) + 가수(52비트)
int 크기는 32비트이므로 double의 가수 52비트보다 작기 때문에 어떠한 int 값이라도 안전하게 정밀도 손실 없이 double타입으로 변환될 수 있다.
[출처: https://www.tcpschool.com/java/java_generic_concept#google_vignette
참고 문헌: 이것이 자바다]
'Programming Language > Java' 카테고리의 다른 글
[Java/개념] 반복문 (for, while, do-while) (0) | 2024.10.08 |
---|---|
[Java/개념] 조건문 (if ~ else / switch) (0) | 2024.10.08 |
[Java/개념] 자바 연산자 (Operators) (0) | 2024.10.07 |
[Java/개념] 자료형과 변수 (1) | 2024.10.07 |
[Java/개념]JDK와 JRE의 차이 (0) | 2024.10.07 |