프로그래밍/JAVA

[ JAVA ] 다형성 - 참조변수의 형변환

리신 2022. 10. 27. 18:41
반응형

참조형 변수도 형변환이 가능한가?

→ 가능하다.기본형 변수와 같이 참조 변수도 형변환이 가능하다.

단, 조건이 있다. 서로 상속관계이 있는 클래스 사이에서만 가능하다.

 

✅ 참고

바로 위 부모나 바로 밑 자식이 아닌, 부모의 부모인 조부모로도 형변환이 가능하다.

따라서 모든 참조변수는 모든 클래스의 조상인 Object클래스 타입으로 형변환이 가능다.

 

기본형 변수의 형변환에서 작은 자료형에서 큰자료형의 형변환은 생략이 가능 했듯이,

참조형 변수의 형변환에서는 자식타입의 참조변수를 부모타입으로 형변환하는 경우에 형변환을 생략할 수 있다.

 

자식타입 → 부모타입(Up-casting) :  형변환 생략가능
부모타입 → 자식타입(Down-casting) : 형변환 생략불가

 * 참조변수간의 형변환 역시 캐스트연산자를 사용하며, 괄호()안에 변환하고자 하는 타입의 이름(클래스명)을 적어주면 된다.

 

💎예제💎

아래 그림과 같이 Car, FireEngine,Ambulance가 정의되어 있을 때

Car클래스는 FireEngine클래스와 Ambulance클래스의 부모클래스이다.

하지만 FireEngine클래스와 Ambulance클래스는 형제관계는 아니다.

주의 하자! 두 클래스는 아무런 관계도 없는 것이다.

 

Car타입의 참조변수와 FireEngine타입의 참조변수,

Car타입의 참조변수와 Ambulance타입의 참조변수는 형변환이 가능하다.

 

FireEngine f;
Ambulance a;
a = (FireEngine) f;
f = (Ambulance) a;

위 코드는 에러가 난다.

왜? → 위에서 말했다시피 상속 관계가 아닌 클래스간의 형 변환은 불가능하기 때문이다.


Up-casting과 Down-casting의 코드를 보자!

Car car = null;
FireEngine fe = new FireEngine();
FireEngine fe2 = null;

car = fe;
fe2 = (FireEngine)car;

car = fe; 를 보면 형변환이 생략되었다. 자식에서 부모타입으로 업캐스팅

fe2 = (FireEngine) car; 는 형변환을 생략 불가하다.  부모에서 자식타입으로 다운 캐스팅

 

🙄그러면 형변환을 생략할 수 있는 경우와 생략할 수 없는 경우로 나뉘는 걸까?

위의 Car 클래스를 예로 들어본다면,

Car타입의 참조변수 c를 Car타입의 조상인 Object타입의 참조변수로 형변환 하는 것은 참조변수가 다룰 수 있는 멤버의 개수가 실제 인스턴스가 갖고 있는 멤버의 개수보다 적을 것이 분명하므로 문제가 되지 않는다. 그래서 형변환을 생략할 수 있도록 한 것이다.

 

하지만!!

Car타입의 참조변수 c를 자손인 FireEngine타입으로 변환하는 것은 참조변수가 다룰 수 있는 멤버의 개수를 늘리는 것이므로, 

실제 인스턴스의 멤버 개수보다 참조변수가 사용할 수 있는 멤버의 개수가 더 많아지므로 문제가 발생할 가능성이 있다.

 

그래서 자식타입으로의 형변환은 생략할 수 없으며, 형변환을 수행하기 전에 Instanceof연산자를 사용해서 참조변수가 참조하고 있는 실제 인스턴스의 타입을 확인하는 것이 안전하다!!

 

형변환은 참조변수의 타입을 변환하는 것이지 인스턴스를 변환하는 것이 아니기 때문에 참조변수의 형변환은 인스턴스에 아무런 영향을 미치지 않는다.

단지 참조변수의 형변환을 통해서, 참조하고 있는 인스턴스에서 사용할 수 있는 멤버의 범위(개수)를 조절하는 것뿐이다.

 

 

여기서! 형변환을 수행하기 전에 인스턴스의 타입을 확인하는게 왜 중요한걸까?❗❔

예제 코드로 설명해보면,

class CastingTest2{
	Public static void main(String args[]) {
    	Car car = new Car();
        Car car2 = null;
        FireEngine fe = null;
        
        car.drive();
        fe = (FireEngine)car;
        fe.drive();
        car2 = fe;
        car2.deive();
    }
}

이 예제는 컴파일은 성공한다.

하지만 실행 시 에러(ClassCastException)가 발생한다.

에러가 발생한 곳은 'fe (FireEngine) car;' 이다.

 

이유가 뭘까?

→ 발생이유는 형변환에 오류가 있기 때문이다.

그냥 보기에는 문제가 없어보이지만, 문제는 참조변수 car가 참조하고 있는 인스턴스가 Car타입의 인스턴스라는 부분에 있다.

 

다형성에서 배운것 처럼 부모타입의 인스턴스를 자식타입의 참조변수로 참조하는 것은 허용되지 않는다.

 

에러가 발생하지 않게하기 위해서는 'Car car = new Car();''Car car = new FireEngine();' 으로 변경해야한다.

 

* 참고로 컴파일 시에는 참조변수간의 타입만 체크하기 때문에 실행시 오류 발생 x

 

✅ 정리

서로 상속관계이 있는 타입간의 형변환은 양방향으로 자유롭게 수행될 수 있으나,
참조변수가 가리키는 인스턴스의 자식타입으로 형변환은 허용되지 않는다.
그래서 참조변수가 가리키는 인스턴스의 타입이 무엇인지 확인하는 것이 중요하다.

 

반응형