본문 바로가기
JAVA/ETC

객체의 타입 변환

by 자이구 2023. 11. 29.

자바 프로그램은 등호(=)를 중심으로 항상 왼쪽과 오른쪽의 자료형이 일치해야 한다. 

만일 자료형이 서로 다를 때는 컴파일러가 자동으로 타입을 반환해주거나 개발자가 직접 명시적으로 타입을 변환해 줘야 한다.

 

기본 자료형에서 업캐스팅은 범위가 좁은 쪽에서 넓은 쪽으로 캐스팅하는 것을 말하며, 다운 캐스팅은 그 반대이다.

객체에서는 자식 클래스에서 부모 클래스 쪽으로 반환되는 것이 업 캐스팅, 그 반대가 다운 캐스팅이다. 

객체는 항상 업캐스팅할 수 있으므로 명시적으로 적어주지 않아도 컴파일러가 대신 넣어준다. 

하지만 다운캐스팅은 개발자가 직접 명시적으로 넣어 줘야 한다.


 기본 자료형에서 다운캐스팅할 때는 넓은 범위의 값이 좁은 범위로 바뀌어 오차가 발생하지만 문법적으로 문제는 없다.

하지만 객체는 명시적으로 적어 준다고 해도 다운캐스팅 자체가 안될 때가 있다. ClassCastException 예외가 발생한다. 

 

업캐스팅을 말로 표현하면 "고래는 포유류의 한 종류이다."이다. 당연히 성립하는 말이다.

다운캐스팅을 말로 표현하면 "표유류는 고래의 한 종류이다." 항상 성립하는 것은 아니다.

즉 포유류 중에는 고래인 포유류도 있고, 고래가 아닌 포유류도 있다. 

고래인 포유류 객체는 포유류로의 다운캐스팅이 가능할 것이고, 고래가 아닌 포유류 객체는 불가능할 것이다. 

 

포유류 고래1 = new 포유류(); //고래와 고래가 아닌 포유류 모두 포함된 포유류 객체
포유류 고래2 = new 고래();  // 고래인 포유류 객체

 

둘다 포유류 타입의 자료형이지만 실제 힙 메모리에 생성된 객체 모양은 다르다. 

고래1은 실제 포유류 객체로 만들었으므로 여기에는 포유류의 공통된 속성과 기능들만 포함돼 있을 것이다. 

이때 고래1은 고래로의 다운 캐스팅이 불가능 할 것이다.

객체 내부에 포유류의 특성만 가지고 있지 고래로의 확장된 특성을 가지고 있지 않기 때문이다. 

반면 고래2는 실제 고래() 생성자를 이용해 객체를 생성했으므로 객체 내부에는 포유류뿐만 아니라 확장된 고래의 특성도 포함돼 있다. 따라서 고래2도 포유류 자료형으로 저장돼 있지만, 고래로의 다운캐스팅이 가능하다. 

 

캐스팅의 가능 여부는 무슨 타입으로 선언돼 있는지는 중요하지 않으며 어떤 생성자로 생성됐는지가 중요하다. 

실제 생성된 객체의 위쪽(업캐스팅 방향)에 있는 모든 클래스 타입으로는 항상 캐스팅할 수 있다. 


A <- B <- C의 상속 관계를 고려해보자.

A a = new B(); 부분을 살펴보면

상속부분에서 설명 한 것처럼 자식 클래스의 생성자를 호출하면 부모 클래스의 객체를 먼저 생성한다고 했으므로

A객체가 먼저 메모리에 만들어지고, 이후 B객체가 완성될 것이다. 

그림에서 볼 수 있듯이 B객체 속에 A객체를 품고 있는 모양이다. 그런데 이 객체는 A타입의 참조 변수로 가리키고 있다.

이 때 실제 참조 변수는 힙 메모리의 B객체 안에 있는 A객체를 가리키게 된다. 

선언된 타입이 의미한는 바는 실제 객체에서 자신이 선언된 타입의 객체를 가리키게 된다. 

 

B b = (B)a; 부분을 살펴보면

A타입의 a를 B타입으로 캐스팅해 B타입으로 저장하고자 한다. a는 A객체를 가리켰지만, (B) a는 B 가리켜야 하는 것이다.

힙 메모리에는 이미 B객체가 있으므로 B타입을 가리키는 것이 전혀 문제가 없는 것이다.

 

C c = (C)a; 부분을 살펴보면

참조변수 C는 이제 C타입을 가리켜야 하는데, 힙 메모리에는 C타입 객체가 만들어진 적이 없다. 

따라서 C타입으로는 다운 캐스팅할 수 없다. 

 

이와 같은 이유로 캐스팅의 가능 여부를 확인하기 위해 실제 어떤 생성자로 만들었지는지가 중요했던 것이다.  

 

댓글