본문 바로가기

Java 기본 문법/1. 변수, 기본 데이터 타입, 연산자

3. Java 자바 - 자동 타입 변환, 강제 타입 변환

타입 변환

 

자바에는 두 종류의 타입 변환이 있다.

 

- 자동 타입 변환 (묵시적)

 

- 강제 타입 변환 (명시적)

 

 

1. 자동 타입 변환

 

프로그램 실행 도중에 자동으로 타입 변환이 일어난다.

작은 크기 가지는 타입이 큰 크기를 가지는 타입에 저장될 때 발생한다.

 

큰 크기 타입 = 작은 크기 타입

 

 

타입별 크기 순서 (byte)

 

  byte (1) < short (2) < int (4) < long (8) < float (4) < double (8)

 

* float은 표현 범위가 더 크기 때문에 더 큰 타입으로 들어간다.

 

       byte byteVal = 10;

       int intVal = byteVal;   // 자동 타입 변환으로 byteVal 은 int 형으로 변환된다.

 

     (가지고 있는 값 10은 변하지 않음)

 

       int intVal = 20;

       double doubleVal = intVal;  //20.0

 

      실수 타입으로 변환되면 .0 이 붙은 실수값이 된다.

 

       char charVal = 'A';

       int intVal = charVal;    //65 저장됨

 

       char 타입이 int 타입으로 변환되면 유니코드 값이 저장된다.

 

      단, 음수가 저장될 수 있는 byte, int 등의 타입은 char 타입으로 자동 타입 변환할 수 없다!!

   

          byte byteVal = 65;

          char charVal = byteVal;                   // 컴파일 에러!!

          char charData = (char) byteVal;     // 강제 타입 변환은 가능하다.

 

public class PromotionExam {
	public static void main(String[] args) {
    	byte byteVal = 10;
        int intVal = byteVal;   //byte -> int
        System.out.println(intVal);   //10
        
        char charVal = '가';
        intVal = charVal;    //char -> int
        System.out.println("가의 유니코드 : "+intVal);  //가의 유니코드 : 44032
        
        intVal = 500;
        long longVal = intVal;    //int -> long
        System.out.println(longVal);  // 500
        
        intVal = 200;
        double doubleVal = intVal;   //int -> double
        System.out.println(doubleVal);  //200.0
    }
}

 

 

2. 강제 타입 변환 (Casting)

 

큰 크기 타입은 작은 타입으로 자동 타입 변환을 할 수 없다.

하지만 강제로 int 타입의 1 byte 를 잘라서 byte 타입 변수에 저장할 수 있다. (나머지 3byte는 버려지게 된다.)

 

작은 크기 타입 = (작은 크기 타입)큰 크기 타입

 

 

     int intVal = 103029770;        //00000110 00100100 00011100 00001010  (10이 저장됨)

     byte byteVal = (byte)intVal;   //강제 타입 변환

 

     원래 값은 보존되지 못한다. (밑줄 친 비트들만 저장되기 때문!!)

     만약 intVal이 1 byte 크기 내의 값을 가진다면, 값은 보존된다.

 

 

int 타입 역시 char로 자동 타입 변환되지 않기 때문에 강제 타입 변환을 사용한다.

 

       int intVal = 'A';                                 // 65저장

       char charVal = (char)intVal;       // 65에 해당되는 유니코드 문자가 저장된다.

       System.out.println(charVal);     // 저장된 문자 출력

 

실수 타입(float, double)은 정수 타입으로 자동 타입 변환되지 않기 때문에 강제 타입 변환을 사용해야 한다.

 

소수점 이하 부분은 버려지고 (값 손실), 정수 부분만 저장된다.

 

ex) double doubleVal = 3.14;

       int intVal = (int)doubleVal;      // intVal는 doubleVal 의 정수 부분인 3만 저장됨

 

public class CastingExam {
	public static void main(String[] args) {
    
    	int intVal = 44032;
        char charVal = (char)intVal;
        System.out.println(charVal);     // 44032에 해당되는 유니코드 '가' 출력
        
        long longVal = 500;
        intVal = (int)longVal;
        System.out.println(intVal);      // 500 1byte 이내로 손실없음
        
        double doubleVal = 3.14;
        intVal = (int)doubleVal;
        System.out.println(intVal);      // 정수부분인 3 출력
    }
}

 

 

강제 타입 변환에서 사용자로 부터 받은 입력값을 변환할 때 값의 손실이 일어나지 않도록 주의해야한다.

따라서 값이 보존할 수 있는지 체크할 필요가 있다.

 

public class CheckValBeforeCasting {
	public static void main(String[] args) {
    
    	int i = 128;  //변환 대상
        
        if ( (i < Byte.MIN_VALUE) || (i > Byte.MAX_VALUE) ) {  // (i<-128 || i>127) 과 동일
        	System.out.println("byte 타입으로 변환 할 수 없습니다.");
            System.out.println("값을 다시 확인하세요");
        } else {
        	byte b = (byte) i;
            System.out.println(b);
        }
    }
}

 

 

자바에서 데이터 값 검사를 위해 해당 타입의 최대값, 최소값 상수를 제공한다.

 

기본 타입

최대값 상수

최소값 상수

byte

Byte.MAX_VALUE

Byte.MIN_VALUE

short

Short.MAX_VALUE

Short.MIN_VALUE

int

Int.MAX_VALUE

Int.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 FromIntToFloat {
	public static void main(String[] args) {
    	int num1 = 123456780;
        int num2 = 123456780;
        
        float num3 = num2;  //int 변수 num2 를 float로 자동 변환
        num2 = (int)num3;   //float 변수를 int형으로 강제 변환
        
        int result = num1 - num2;
        
        System.out.println(result);    // -4 가 출력된다!?
    }
}

 

위의 예제에서 결과 값이 0이 나와야 의미상 정상이지만 -4가 출력된다.

 

int 값을 float타입으로 자동 변환 하면서 문제 발생!

float 형의 가수 부분은 23비트 이므로, 123456780은 23비트로 표현할 수 없어서 근사치로 변환된다.

(정밀도 손실 발생)

 

float 값을 다시 int 타입으로 변환하면 원래의 int 값을 얻지 못한다.

 

따라서 num1 과 num2는 동일한 값이 아니게 된다.

 

해결책은 float 대신 double 타입을 사용하면 된다.

 

 

3. 연산식에서의 자동 타입 변환과 강제 타입 변환

 

서로 다른 타입의 피연산자가 있을 경우 두 연산자 중 크기가 큰 타입으로 자동 타입 변환된 후 연산을 수행한다.

 

int intVal = 10;

double doubleVal = 5.5;

double result = intVal + doubleVal;      // result 에 15.5 저장됨

 

여기서 intVal 는 double 형으로 자동 타입 변환된다.

 

int 타입으로 연산을 해야 한다면 double 타입을 int 타입으로 강제 변환 후 연산을 수행하면 된다.

 

int intVal = 10;

double doubleVal = 5.5;

int result = intVal + (int)doubleVal;    //result에 15가 저장됨 (소수점 버려짐)

 

public class OperationPromotionExam {
	public static void main(String[] args) {
    	
        byte byteVal1 = 10;
        byte byteVal2 = 20;
        // byte byteVal3 = byteVal1 + byteVal2;  컴파일 에러 연산결과가 int형 이기 때문!
        
        int intVal1 = byteVal1 + byteVal2;
        System.out.println(intVal1);
        
        char charVal1 = 'A';
        char charVal2 = 1;
        // char charVal3 = charVal1 + charVal2;  컴파일 에러 연산결과가 int형 이기 때문!
        
        int intVal2 = charVal1 + charVal2;                 // 65 + 1
        System.out.println("유니코드 = " +intVal2);        // 66
        System.out.println("출력문자 : "+(char)intVal2);   // B
        
        int intVal3 = 10;
        int intVal4 = intVal3 / 4;     // int형 연산, 소수점 버려짐
        
        System.out.println(intVal4);   // 2
        
        int intVal5 = 10;
        // int intVal6 = 10 / 4.0;   컴파일 에러 연산결과가 double 이기 때문
        double doubleVal = intVal5 / 4.0;
        
        System.out.println(doubleVal);   // 2.5
    }
}        

 

자바는 정수 연산 시 int 타입을, 실수 연산 시 double 타입을 기본으로 한다.

 

피연산자를 4byte 단위로 저장하기 때문에,

4byte보다 작은 타입 (byte, char, short)는 int로 변환되어 연산이 수행된다.

 

 

연산의 결과도 int형으로 반환된다.

 

   char ai = 'A';   // 유니코드 65

   int result = ai + 1;   //'A'의 유니코드보다 1이 큰 유니코드 66 저장됨 (덧셈 연산)

   char na = (char) result;   //'B'가 저장된다.

 

만약 피연산자중 long 타입이 있다면, 다른 피연산자도 long 타입이 되고, 연산 결과도 long 타입으로 반환된다.

 

실수 타입 float 와 double도 마찬가지로 적용된다.

피연산자중 double 타입이 있다면,

다른 피연산자도 double 타입이 되고, 연산 결과도 double 타입으로 반환된다.

 

 

* 연산 시 자동 타입 변환 정리

- 정수와 실수 연산 = 실수형 타입 (double)

- 정수와 정수 연산 = int 타입

- 실수와 실수 연산 = double 타입

- 큰 타입과 작은 타입 연산 = 큰 타입

 

 

  • lily 2020.11.15 02:29

    혹시 왜 char는 short로 자동 타입 변환이 되지 않는지 알려주실수 있으신가요

    • Favicon of https://kephilab.tistory.com kephi 2020.11.19 14:49 신고

      short과 char은 모두 2 byte의 크기를 갖지만, short의 범위는 (-32768~32767)이고 char의 범위는 (0~65535)이므로 서로 범위가 달라서 둘 중 어느 쪽으로의 형변환도 값 손실이 발생할 수 있으므로 자동적으로 형변환이 수행될 수 없습니다.