Java

[자바의 정석] #CH.2 변수 Variable - 2.5 형변환

소댓 2023. 1. 18. 12:32

5. 형변환

5.1 형변환(캐스팅, casting)이란?

- 형변환 : 변수 또는 상수의 타입을 다른 타입으로 변환하는 것

> int타입의 값과 float타입의 값을 더하는 경우, 먼저 두 값을 같은 타입으로 즉, 둘 다 float 타입으로 변환한 후에 더함

 

5.2 형변환 방법

- 형변환하고자 하는 변수나 리터럴의 앞에 변환하고자 하는 타입의 괄호를 함꼐 붙여줌

> (타입)피연산자

1
2
3
4
5
6
7
 
double d = 85.4;
int score = (int)d; // double 타입의 변수 d를 int타입으로 형변환
 
int score = (int)85.4; // 변수 d의 값을 읽어 와서 형변환한다.
int score = 85; // 형변환의 결과인 85를 변수 score에 저장
 
cs

>> 피연산자인 변수 d의 값은 형변환 후에도 아무런 변화가 없다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
 
public class CastingEx1_ {
 
    public static void main(String[] args) {
        double d = 85.4;
        int score = (int)d;
        
        System.out.println("score="+score);
        System.out.println("d+"+d);
    }
 
}
 
cs
더보기

score=85
d+85.4 → 형변환 후에도 피연산자에는 아무런 변화가 없음

 

* 기본형간의 형변환

- int → char

> 수식 : (char) 65 

> 결과 : 'A'

- char → int

> 수식 : (int) 'A'

> 결과 : 65

- float → int (> 소수점 이하 값은 버림으로 처리)

> 수식 : (int) 1.6f

> 결과 : 1

- int → float

> 수식 : (float) 10

> 결과 : 10.0f

 

 

5.3 정수형간의 형변환

- 큰 타입에서 작은 타입으로의 변환(ex. int타입 → byte타입)하는 경우, '값손실(loss of data)'이 발생할 수 있음

- 작은 타입에서 큰 타입으로의 변환(ex. byte타입 → int타입)하는 경우, 값손실 발생 x, 나머지 빈 공간은 0이나 1로 채움

> 남은 빈 공간은 보통 0으로 채우지만, 변환하려는 값이 음수인 경우에는 빈 공간을 1로 채움(부호를 유지하기 위해)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
public class CastingEx2 {
 
    public static void main(String[] args) {
        int i = 10;
        byte b = (byte)i;
        System.out.printf("[int -> byte] i=%d -> b=%d%n", i, b);
        
        i = 300;
        b = (byte)i; // 값손실 있음
        System.out.printf("[int -> byte] i=%d -> b=%d%n", i, b);
        
        b = 10;
        i = (int)b;
        System.out.printf("[byte -> int] b=%d -> i=%d%n", b, i);
    
        b = -2;
        i = (int)b;
        System.out.printf("[byte -> int] b=%d -> i=%d%n", b, i);
        
        System.out.println("i="+Integer.toBinaryString(i));
    }
 
}
 
cs

 

더보기

[int -> byte] i=10 -> b=10
[int -> byte] i=300 -> b=44
[byte -> int] b=10 -> i=10
[byte -> int] b=-2 -> i=-2
i=11111111111111111111111111111110

 

 

 

5.4 실수형 간의 형변환

 

- 실수형에서도 정수형처럼 작은 타입에서 큰 타입으로 변환하는 경우, 빈 공간을 0으로 채움

 

- float 타입→ double 타입 변환 

> 지수(E) : float의 기저인 127을 뺀 후 double의 기저인 1023을 더해서 변환

> 가수(M) : float의 가수 23자리를 채우고 남은 자리를 0으로 채움

 

- double 타입→ float 타입 변환 

> 지수(E) : double의 기저인 1023을 뺀 후 float의 기저인 127을 더함

> 가수(M) : double의 가수 52자리 중 23자리만 저장되고 나머지는 버려짐

 

>> 형변환할 때, 가수의 24번째 자리에서 반올림이 발생할 수 있음

(24번째 자리의 값이 1이면, 반올림이 발생하여 23번째 자리의 값이 1 증가)

 

>> float 타입의 범위를 넘는 값을 float로 형변환하는 경우는 '+-무한대' 또는 '+-0'을 결과로 얻음

1
2
3
4
5
double d = 1.0e100; // float의 최대값보다 큰 값을 d에 저장(1.0x10^100)
float f = (float)d; // d의 값을 float으로 형변환해서 f에 저장. f는 무한대가 된다.
 
double d = 1.0e-50; // float의 최소값보다 작은 값을 d에 저장(1.0x10^-50)
float f = (float)d; // f의 값은 0이 된다.
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
public class CastingEx3_ {
 
    public static void main(String[] args) {
        float f = 9.1234567f;
        double d = 9.1234567;
        double d2 = (double)f;
        
        System.out.printf("f =%20.18f\n", f);
        System.out.printf("d =%20.18f\n", d);
        System.out.printf("d2 =%20.18f\n", d2); 
    }
 
}
 
cs
더보기

f =9.123456954956055000
d =9.123456700000000000
d2 =9.123456954956055000

 

 

5.5 정수형과 실수형 간의 형변환

 

* 정수형을 실수형으로 변환

: 정수를 2진수로 변환한 다음 정규화를 거쳐 실수의 저장형식으로 저장

- 실수형의 정밀도 제한으로 인한 오차가 발생할 수 있음

> 따라서, 10진수로 8자리 이상의 값을 실수형으로 변환할 때는 float가 아닌 double로 형변환을 해야 함

 

* 실수형을 정수형으로 변환

: 정수형의 표현 형식으로 소수점 이하의 값은 표현할 수 없기 때문에, 실수형의 소수점이하 값을 버려짐

> 그래서 실수형을 정수형으로 형변환할 때는 반올림이 발생하지 않음

>> 만약 실수의 소수점을 버리고 남은 정수가 정수형의 저장범위를 넘는 경우에는 정수의 오버플로우가 발생

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
public class CastingEx4_ {
 
    public static void main(String[] args) {
        int i = 91234567// 8자리의 10진수
        float f = (float)i; // int를 float로 형변환
        int i2 = (int)f; // float를 다시 int로 형변환
        
        double d = (double)i; // int를 다시 double로 형변환
        int i3 = (int)d; // double을 다시 int로 형변환
        
        float f2 = 1.666f;
        int i4 = (int)f2;
        
        System.out.printf("i=%d\n", i);
        System.out.printf("f=%f i2=%d\n", f, i2);
        System.out.printf("d=%f i3=%d\n", d, i3);
        System.out.printf("(int)%f=%d\n", f2, i4);
    }
 
}
 
cs
더보기

i=91234567
f=91234568.000000 i2=91234568
d=91234567.000000 i3=91234567
(int)1.666000=1

 

 

5.6 자동 형변환

 

- 서로 다른 타입간의 대입이나 연산을 할 때, 편의상 형변환이 생략된 경우에는 컴파일러가 형변환을 자동적으로 추가함

1
2
3
 
float f = 1234; // 형변환의 생략. float f = (float)1234;
 
cs

 

- 변수가 저장할 수 있는 값의 범위보다 더 큰 값을 저장하려는 경우에 형변환을 생략하면, 에러가 발생

1
2
3
 
byte b = 1000; // 에러. byte의 범위(-128~127)를 넘는 값을 저장.
 
cs

- 에러 메시지 : incompatible types: possible lossy conversion from int to byte

> 큰 타입에서 작은 타입으로의 형변환은 값 손실이 발생할 수 있다는 뜻

 

- 명시적으로 형변환 해줬을 경우, 형변환이 의도적인 것으로 간주하고 컴파일러는 에러를 발생 시키지 않음

1
char ch = (char)1000; // 명시적 형변환. 에러가 발생하지 않음
cs

 

 

* 산술 변환 : 연산과정에서 자동적으로 발생하는 형변환

- 서로 다른 두 타입의 연산에서는 먼저 타입을 일치시킨 다음에 연산을 수행해야 하므로, 형변환이 자동으로 이루어짐

1
2
int i = 3;
double d = 1.0 + i; // double d = 1.0 + (double)i;에서 형변환이 생략됨 
cs

- 서로 다른 두 타입간의 덧셈에서는 두 타입 중 표현범위가 더 넓은 타입으로 형변환하여 일치시킨 뒤 연산을 수행

  > 값손실의 위험이 더 적어서 올바른 결과를 얻을 수 있음

1
2
3
4
5
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
cs

 

 

* 자동 형변환의 규칙

 

- 컴파일러는 기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환한다.

: 표현범위가 좁은 타입에서 넓은 타입으로 형변환하는 경우에는 값 손실이 없으므로,

  두 타입 중에서 표현범위가 더 넓은 쪽으로 형변환 된다.