본문 바로가기
back-end/JAVA

32) 참조변수의 형변환

by 모두의 향연 2021. 6. 9.
728x90
반응형

32) 참조변수의 형변환

 

1. 참조변수의 형변환

-사용할 수 있는 멤버의 개수를 조절하는 것

기본형의 형변환은 타입이 double인 3.5를 int로 바꾸면 3이 된다. 아예 값이 바뀌어 버렸다. 

하지만 참조변수의 형변환은 주솟값이나 객체가 바뀌는 게 아니고 멤버의 개수가 바뀐다. 

 

-조상·자손 관계의 참조변수는 서로 형변환 가능(자손끼리는 불가능)

1
2
3
4
class Car{}
class FireEngine extends Car{}
class Ambulance extends Car{}
cs
상속계층도

조상인 Car와 자손인 FireEngine, 조상인 Car와 자손인 Ambulance끼리는 서로 형변환이 가능하나, 자손끼리는 형변환이 불가능하다.

 

2. 예시

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
26
27
28
29
30
31
32
33
class Car{
    String color;
    int door;
    
    void drive() {
        System.out.println("갑니다!");
    }
    void stop() {
        System.out.println("멈춥니다!");
    }
}
 
class FireEngine extends Car{
    void water() {
        System.out.println("물!");
    }
}
 
class Ambulance extends Car{
    
}
 
public class Test {
    public static void main(String[] args) {
        FireEngine f = new FireEngine();//소방차 객체생성
        
        Car c = (Car)f;//OK.조상인 Car타입으로 형변환(생략가능)
        FireEngine f2 = (FireEngine)c;//OK.자손인 FireEngine타입으로 형변환(생략불가)
        Ambulance a = (Ambulance)f;//에러. 상속관계가 아닌 클래스 간의 형변환 불가
    }
}
 
 
cs
  

이 코드를 도식화하면,

도식화

27행| Car c = (Car)f;에서 참조변수 f의 주솟값을 Car의 참조변수 c에 넣습니다. 그럼 f의 주솟값이 복사되어 c에 넣어지겠죠. 타입이 일치하지 않으니 f의 형을 Car로 바꿔줍니다. Car와 FireEngine은 부모·자식관계이므로 서로 형변환 가능합니다. 

다만, FireEngine에서 Car로 형변환할 때 생략이 가능한데, 멤버개수가 줄어드는 것이기 때문에 생략이 가능한 겁니다. 

c가 접근 가능한 멤버변수는 color, door, drive(), stop() 이렇게 4개만 접근 가능합니다.

같은 객체를 가리키고 있긴 하지만 c라는 리모콘으로는 4개밖에 접근 못합니다.

참조변수의 형변환으로 접근 가능한 멤버개수를 바꿨네요.

28행| FireEngine f2 = (FireEngine)c;에서 참조변수 c의 주솟값을 FireEngine의 참조변수 f2에 넣습니다. 타입이 일치하지 않으니 c의 형을 FireEngine으로 바꿔줍니다. Car와 FireEngine은 부모·자식관계이므로 서로 형변환 가능합니다. 

다만, Car에서 FireEngine으로 형 변환할 때는 생략이 불가능합니다. 멤버개수가 늘어나는 것이기 때문에 생략할 수 없습니다. f2가 접근 가능한 멤버변수는 color, door, drive(), stop(), water() 이렇게 5개 모두 접근 가능합니다. 

 

(그냥 형 변환을 써주세요... 그냥 씁시다. 차라리 그게 편해요)

 

29행| Ambulance a = (Ambulance)f;에서는 f는 FireEngine의 참조변수이고 a는 Ambulance의 참조변수입니다. 자손끼리는 형변환이 불가능하므로 에러가납니다. 형제관계는 형변환 불가!

 

다 같은 객체를 가리키지만 형변환에 따라 접근할 수 있는 멤버개수가 달라집니다.

차이는 형변환 시 생략 가능하냐 마냐.

f가 참조할 수 있는 멤버개수: 5개

c가 참조할 수 있는 멤버개수: 4개

f2가 참조할 수 있는 멤버개수: 5개

 

 

3) 주의할 점

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
26
27
28
29
class Car{
    String color;
    int door;
    
    void drive() {
        System.out.println("갑니다!");
    }
    void stop() {
        System.out.println("멈춥니다!");
    }
}
 
class FireEngine extends Car{
    void water() {
        System.out.println("물!");
    }
}
 
public class Test {
    public static void main(String[] args) {
        Car c = null;
        FireEngine f = new FireEngine();
        FireEngine f2 = (FireEngine)c;
        Car c2 = (Car)f2;
        c2.drive();//NullPointerException발생
    }
}
 
 
cs

25행| c2.drive();//NullPointerException발생c2의 주솟값은 null이고 그에 따라 객체도 없으므로 실행에러가 발생한다. 컴파일러는 형변환 연산자만 써주면(타입만 일치시키면) 그게 형변환 이전의 객체에서 왔는지 알지 못한다. 연산자소스코드상엔 오류라고 안 뜨지만 컴파일하면 실행에러가 발생한다.

형변환 시 주의할점은 형변환이 중요한게 아니라, 실제 객체가 어떤건지가 중요하다.

 

 

 

 

*유튜브 남궁성 선생님의 `자바의 정석`을 참고하여 만들었습니다*
*자세히 보고 싶은 분들은 유튜브 가서 보시면 됩니다*

728x90
반응형