본문 바로가기

Study

[JAVA/자바] 형변환

형변환

- 작은 범위에서 큰 범위로는 당연히 값을 넣을 수 있다. 예) int -> long -> double

- 큰 범위에서 작은 범위는 다음과 같은 문제가 발생할 수 있다. (소수점 버림, 오버플로우)

 

작은 범위에서 큰 범위로 대입은 허용한다.

자바에서 숫자를 표현할 수 있는 범위는 다음과 같다.

int < long < double

int보다는 long이, long보다는 double이 더 큰 범위를 표현할 수 있다.

 

자바는 기본적으로 같은 타입에 값을 대입할 수 있다. 그런데 다른 타입에 값을 대입하면 어떻게 될까?

- int -> long을 비교해 보면 long이 int보다 더 큰 숫자 범위를 표현한다.

작은 범위 숫자 타입에서 큰 범위 숫자 타입에 대입을 하면 문제가 되지 않는다.

만약 이런 경우까지 오류가 발생한다면 개발이 너무 불편할 것이다.

- long -> double의 경우에도 double은 부동 소수점을 사용하기 때문에 더 큰 숫자 범위를 표현한다. 따라서 대입할 수 있다.

- 정리하자면 작은 범위에서 큰 범위로의 대입은 자바 언어에서 허용한다.

쉽게 이야기하면 큰 그릇은 작은 그릇에 담긴 내용물을 담을 수 있다.

 

자동 형변환

하지만 결국 대입하는 형(타입)을 맞추어야 하기 때문에 개념적으로는 다음과 같이 동작한다.

// intValue = 10
doubleValue = intValue
doubleValue = (double) intValue // 형 맞추기
doubleValue = (double) 10 // 변수 값 읽기
doubleValue = 10.0 // 형 변환

이렇게 앞에 (double)과 같이 적어주면 int 형이 double 형으로 형이 변한다. 이렇게 형이 변경되는 것을 형변환이라 한다. 작은 범위 숫자 타입에서 큰 범위 숫자 타입으로의 대입은 개발자가 이렇게 직접 형변환을 하지 않아도 된다.

이런 과정이 자동으로 일어나기 때문에 자동 형변환, 또는 묵시적 형변환이라 한다.

 

명시적 형변환

이번에는 반대로 큰 범위에서 작은 범위로 대입해 보자. 큰 범위에서 작은 범위 대입은 명시적 형변환이 필요하다.

 

double은 실수를 표현할 수 있다. 따라서 1.5가 가능하다. 그런데 int는 실수를 표현할 수 없다.

이경우 double -> int는 대입하면 어떻게 될까? 컴파일 오류가 발생한다.

 

하지만 만약 이런 위험을 개발자가 직접 감수하고도 값을 대입하고 싶다면 데이터 타입을 강제로 변경할 수 있다.

예를 들어서 대략적인 결과를 보고 싶은데, 이때 소수점을 버리고 정수로만 보고 싶을 수 있다.

 

형변환은 다음과 같이 변경하고 싶은 데이터 타입을 (int)와 같이 괄호를 사용해서 명시적으로 입력하면 된다.

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

이것은 형(타입)을 바꾼다고 해서 형변환이라 한다. 영어로는 캐스팅이라 한다. 

그리고 개발자가 직접 형변환 코드를 입력한다고 해서 명시적 형변환이라 한다.

 

"캐스팅"은 영어 단어 "cast"에서 유래되었다. "cast"는 금속이나 다른 물질을 녹여서 특정한 형태나 모양으로 만드는 과정을 의미한다.

 

명시적 형변환 과정

// 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 maxIntOver = 2147483648L; // int 최고값 + 1 (초과)
        int intValue = 0;

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

long maxIntOver = 2147483648L를 보면 int로 표현할 수 있는 가장 큰 숫자보다 1 큰 숫자를 입력했다.

이 숫자는 리터럴은 int 범위를 넘어가기 때문에 마지막에 L을 붙여서 long 형을 사용해야 한다.

이 경우 int로 표현할 수 있는 범위를 넘기 때문에 다음과 같이 long -> int로 형변환 하면 문제가 발생한다.

 

- 결과를 보면 -2147483648이라는 전혀 다른 숫자가 보인다. int 형은 2147483648L를 표현할 수 있는 방법이 없다.

이렇게 기존 범위를 초과해서 표현하게 되면 전혀 다른 숫자가 표현되는데, 이런 형상을 오버플로우라 한다.

- 보통 오버플로우가 발생하면 마치 시계가 한 바퀴 돈 것처럼 다시 처음부터 시작한다.

참고로 -2147483648 숫자는 int의 가장 작은 숫자이다.

- 중요한 것은 오버플로우가 발생하는 것 자체가 문제라는 점이다!

오버플로우가 발생했을 때 결과가 어떻게 되는지 계산하는데 시간을 낭비하면 안 된다!

오버플로우 자체가 발생하지 않도록 막아야 한다.

이 경우 단순히 대입하는 변수(intValue)의 타입을 int -> long으로 변경해서 사이즈를 늘리면 오버플로우 문제가 해결된다.

 

 

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

 

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

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

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

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

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

 

 

정리

 

형변환

int -> long -> double

 

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

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

 

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

- 소수점 버림

- 오버플로우

 

연산과 형변환

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

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

'Study' 카테고리의 다른 글

[JAVA/자바] Scanner  (0) 2023.05.10
java: incompatible types: possible lossy conversion from double to int  (0) 2023.05.08
[JAVA/자바] 스코프  (0) 2023.04.19
[JAVA/자바] 반복문  (0) 2023.04.06
[JAVA/자바] 조건문  (0) 2023.03.31