개발

자바의 형변환(자동형변환, 명시적형변환)

이웃집퉁퉁이 2024. 6. 17. 00:07

숫자 타입

//정수
 byte b = 127; //-128 ~ 127
 short s = 32767; // -32,768 ~ 32,767
 int i = 2147483647; //-2,147,483,648 ~ 2,147,483,647 (약 20억)
 long l = 9223372036854775807L; //-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
 
 //실수
 float f = 10.0f;
 double d = 10.0;

표현할 수 있는 숫자의 범위와 차지하는 메모리 공간은 다음과 같다.

 - byte : -128 ~ 127 (1byte, 2⁸)

 -  short : -32,768 ~ 32,767 (2byte, 2¹⁶)

 -  int : -2,147,483,648 ~ 2,147,483,647 (약 20억) (4byte, 2³²)

 -  long : -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 (8byte, 2⁶⁴)

실수형

 -  float : 대략 -3.4E38 ~ 3.4E38, 7자리 정밀도 (4byte, 2³²)

 -  double : 대략 -1.7E308 ~ 1.7E308, 15자리 정밀도 (8byte, 2⁶⁴)

형변환1 - 자동 형변환(명시적 형변환)

작은 범위에서 큰 범위로의 대입은 자바 언어에서 자동으로 형 변환이 이루어진다.

큰 범위에서는 작은 범위를 표현하는데 문제가 없기 때문이다.

예) 작은 박스의 짐들을 큰 박스에 담는데는 문제가 없다.

int -> long, long -> double은 문제없이 이루어진다.

int intValue = 10;
double doubleValue = intValue; // 자동 형 변환(묵시적 형 변환)
// double doubleValue = (double) intValue; // 명시적 형 변환

 

형변환2 - 묵시적 형변환

반대로 큰 범위에서 작은 범위로 대입은 어떻게 될까? 

불가능하다.  // 자동 형변환이 이루어지지 않는다. 

예) 큰 박스의 짐들을 작은 박스에 전부 담을 수 없다.

 

double 은 실수를 표현할 수 있지만, int는 실수를 표현할 수 없다.

double의 실수값 1.5를 int로 표현할 수는 없다.

 

큰 범위에서 작은 범위로의 대입은 자동 형변환이 이루어지지 않고, 아래와 같은 오류가 발생한다.

double doubleValue = 1.5;

int intValue = = doubleValue; //컴파일 오류 발생

//java: incompatible types: possible lossy conversion from double to int
//java: 호환되지 않는 유형: double에서 int로의 가능한 손실 변환

 

 

아래와 같은 방식으로 명시적 형변환이 가능하다.

double doubleValue = 1.5;

int intValue = (int) doubleValue; //형변환

 

그렇다면 이때 intValue의 값은 어떻게 될까?

double 타입이 아니므로 실수값 1.5를 그대로 보존할 수 없다.

int에서는 1 값이 남게 된다.

 

형변환과 오버플로우

형변환을 할 때 만약 작은 숫자가 표현할 수 있는 범위를 넘어서면 어떻게 될까?

int의 최댓값은 2147483647이다. 여기에 1을 더한 2147483648을 int 타입에 대입하면 어떻게 될까?

아래 테스트를 보면, -2147483648 값이 담기게 된다.

(int의 표현 범위는 -2,147,483,648 ~ 2,147,483,647 이다)

long maxIntValue = 2147483647; //int 최고값
long maxIntOver = 2147483648L; //int 최고값 + 1(초과)

int intValue = 0;

intValue = (int) maxIntValue; //형변환
System.out.println("maxIntValue casting=" + intValue); //출력:2147483647

intValue = (int) maxIntOver; //형변환
System.out.println("maxIntOver casting=" + intValue); //출력:-2147483648

결과를 확인하면 -2147483648이라는 예상치 못한 숫자가 나타납니다. 

int 형은 2147483648을 표현할 수 없기 때문에, 완전히 다른 값이 나타나게 됩니다. 

이처럼 허용 범위를 넘어서는 값을 표현하려 할 때, 완전히 다른 숫자가 나타나는 현상을 오버플로우라고 합니다. 

 

계산과 형변환

형변환은 대입뿐만 아니라, 계산을 할 때도 발생한다.

int div1 = 3 / 2;
System.out.println("div1 = " + div1); //1
// int들의 계산결과 int

double div2 = 3 / 2;
System.out.println("div2 = " + div2); //1.0
// int들의 계산결과 int를 double로 자동형변환

double div3 = 3.0 / 2;
System.out.println("div3 = " + div3); //1.5
// int값 2가 double로 자동 형변환되어, 계산결과 double

double div4 = (double) 3 / 2;
System.out.println("div4 = " + div4); //1.5
// int값 2가 double로 자동 형변환되어, 계산결과 double

int a = 3;
int b = 2;
double result = (double) a / b;
System.out.println("result = " + result); //1.5
// a값이 double로 명시적형변환, 이에 따라 b가 int>double로 자동형변환되어 , 계산결과 double

자바에서 계산은 다음 2가지를 기억하자.

1. 같은 타입끼리의 계산은 같은 타입의 결과를 낸다.

 - int + int는 int를, double + double 은 double의 결과가 나온다.

2. 서로 다른 타입의 계산은 큰 범위로 자동 형변환이 일어난다.

 - int + long 은 long + long으로 자동 형변환이 일어난다.

 - int + double 은 double + double로 자동 형변환이 일어난다.


정리

int -> long -> double

작은 범위에서 큰 범위로는 대입할 수 있다.

 - 이것을 묵시적 형변환 또는 자동 형변환이라 한다.

큰 범위에서 작은 범위의 대입은 다음과 같은 문제가 발생할 수 있다. 이때는 명시적 형변환을 사용해야 한다.

 - 소수점 버림

 - 오버플로우

연산과 형변환

 - 같은 타입은 같은 결과를 낸다.

 - 서로 다른 타입의 계산은 큰 범위로 자동 형변환이 일어난다.


생각해 보자

Q1) 왜 하필 int의 최댓값(2147483647)를 1 초과하였을 때 -2147483648 라는 값이 나왔을까?

byte를 예로 들면 최대값 127은 아래와 같이 이진수로 표현될 것이다.

0 1 1 1 1 1 1 1
// 0 = 양의 부호
// 1 1 1 1 1 1 1 = 127
// 결과: +127

여기에서 해당 이진수에 값이 1 증가한다면 아래와 같이 될 것이다.

1 0 0 0 0 0 0 0
// 1 = 음의 부호
// 1 0 0 0 0 0 0 0 = 2의 보수 표현 방식에서 해당 값은 -128을 의미한다.

Q2) 왜 작은 범위에서 큰 범위로의 형 변환은 자동으로 되면서, 큰 범위에서 작은 범위로의 형변환은 자동으로 되지 않고 명시적으로 해야 하는 걸까?

이유는 당연할 듯하다. 작은 범위에서 큰 범위로 타입을 변환할 때는 실제 데이터(값)의 유실이 없기 때문에 큰 문제가 없을 것이다.

하지만 큰 범위에서 작은 범위로 타입을 변환할 때는 실제 데이터(값)의 유실 가능성이 존재한다. 그렇기 때문에 개발자에게 선택권을 넘기는 것이라고 생각한다.

예) 너 long -> int로 형 변환하면 문제가 생길 수 있는데 그래도 할 거야?

 


해당 내용은 아래 강의를 내용으로 작성되었습니다. (인프런 김영한 님의 자바 기초 강의)

https://www.inflearn.com/course/%EA%B9%80%EC%98%81%ED%95%9C%EC%9D%98-%EC%9E%90%EB%B0%94-%EC%9E%85%EB%AC%B8/dashboard