728x90
하위 클래스로 형 변환, 다운 캐스팅이란?
- 앞에서 상위 클래스로 형 변환이 묵시적으로 이루어지는 과정을 알아보았습니다.
- 여기에서는 다시 하위 클래스로 형 변환이 진행되는 과정을 살펴보겠습니다.

- 위 그림과 같은 계층 구조에서 다음과 같이 자료형을 선언했다고 생각해 보겠습니다.
Animal ani = new Human( );
- 이때 생성된 인스턴스 Human 은 Animal 형입니다.
- 자연스럽게 Human 은 Animal 클래스에서 선언한 메서드와 멤버 변수만 사용할 수 있습니다.
- 다른 말로 하자면, Human 클래스에 더 많은 메서드가 구현되어 있고 다양한 멤버 변수가 있다고 하더라도 자료형이 Animal 형인 Human 은 사용할 수 없다는 것을 의미합니다.
- 필요에 따라 다시 원래 인스턴스의 자료형으로 되돌아가서 인스턴스 클래스에서 선언한 멤버 변수와 메서드를 사용해야 할 때가 있습니다.
- 이렇게 상위 클래스 형으로 형 변환되었던 하위 클래스를 다시 원래 자료형으로 형 변환하는 것을 다운 캐스팅(down casting)이라고 합니다.
instanceof 란?
- instanceof 는 다운 캐스팅을 할 때 꼭 필요한 존재입니다. 왜 필요한지부터 이해하고 가겠습니다.
- 상속 관계를 생각해 보면 모든 인간은 동물이지만 모든 동물이 인간은 아닙니다.
- 따라서 다운 캐스팅을 하기 전에 상위 클래스로 형 변환된 인스턴스의 원래 자료형을 확인해야 다운 캐스팅 변환할 때 오류를 막을 수 있습니다.
- 이를 확인하는 예약어가 바로 Instanceof 입니다.
- instanceof 는 다음과 같이 사용할 수 있습니다.
Animal hAnimal = new Human( );
if (hAnimal instanceof Human) {
Human human = (Human)hAnimal;
human.move();
}
- 위 코드에서 사용한 참조 변수 hAnimal 은 원래 Human 형으로 생성되었는데, Anumal 형으로 묵시적 클래스 형 변환이 되었습니다.
- instanceof 예약어는 왼쪽에 있는 변수의 원래 인스턴스형이 오른쪽 클래스 자료형인가를 확인합니다.
- 다른 말로 하면, hAnimal 이 현재는 Animal 자료형으로 되어있지만, 원래는 Human 형으로 생성된 인스턴스인지 확인하는 것입니다.
- 여기서 재미있는 점은 instanceof 로 인스턴스형을 확인하지 않으면 컴파일 오류가 아니라 런타임 오류가 발생한다는 점입니다.
Animal ani = new Tiger();
Human h = (Human)ani;
- 원래 자료형이 Human 이 아닌 참조 변수 ani 를 Human 자료형으로 다운 캐스팅을 하면 컴파일 오류는 나지 않습니다.
- 왜냐하면 일단 Animal 자료형으로 묵시적 자동 형 변환이 진행된 Tiger 의 인스턴스는 강제적으로 Human 형으로 형 변환이 되었습니다. 해당 ani 변수가 강제적으로 Human 형으로 형 변환이 되었으니 마찬가지로 Human 자료형인 h 변수에 대입하는 것에 문제는 없습니다.
- 그런데 이 코드를 실행하면 실행 오류가 발생합니다.
- 따라서 참조 변수의 원래 인스턴스 형을 정확히 확인하고 다운 캐스팅을 해야 안전하며 이때 instanceof 예약어를 사용합니다.
- 아무튼 if 문을 따라서 instanceof 의 반환 값이 true 면 다운 캐스팅을 진행하는데,
Human human = (Human)hAnimal;
위 코드와 같이 명시적으로 자료형을 써주어야 합니다. - 왜냐하면 상위 클래스로는 묵시적으로 형 변환이 되지만, 하위 클래스로 형 변환을 할 때는 명시적으로 해야 하기 때문입니다.
- 동물 클래스를 예시로 보면서 이해해보도록 하겠습니다.
package polymorphism;
import java.util.ArrayList;
class Animal2 {
public void move() {
System.out.println("동물이 움직입니다.");
}
}
class Human2 extends Animal2 {
@Override
public void move() {
System.out.println("사람이 두 발로 걷습니다.");
}
public void readBook() {
System.out.println("사람이 책을 읽습니다.");
}
}
class Tiger2 extends Animal2 {
@Override
public void move() {
System.out.println("호랑이가 네 발로 뜁니다.");
}
public void hunting() {
System.out.println("호랑이가 사냥을 합니다.");
}
}
class Eagle2 extends Animal2 {
@Override
public void move() {
System.out.println("독수리가 하늘을 납니다.");
}
public void flying() {
System.out.println("독수리가 날개를 쭉 펴고 멀리 날아갑니다.");
}
}
public class AnimalTest2 {
ArrayList<Animal2> aniList = new ArrayList<Animal2>();
public static void main(String[] args) {
AnimalTest2 aTest = new AnimalTest2();
aTest.addAnimal();
System.out.println("원래 형으로 다운 캐스팅");
}
public void addAnimal() {
aniList.add(new Human2());
aniList.add(new Tiger2());
aniList.add(new Eagle2());
for (Animal2 ani : aniList) {
ani.move();
}
}
public void testCasting() {
for (int i = 0; i < aniList.size(); i++) {
Animal2 ani = aniList.get(i);
if (ani instanceof Human2) {
Human2 h = (Human2)ani;
h.readBook();
} else if (ani instanceof Tiger2) {
Tiger2 t = (Tiger2)ani;
t.hunting();
} else if (ani instanceof Eagle2) {
Eagle2 e = (Eagle2)ani;
e.flying();
} else {
System.out.println("지원되지 않는 형입니다.");
}
}
}
}

- 위 코드를 한번 살펴보겠습니다.
- 각 동물 클래스를 인스턴스로 생성하여 Animal 형으로 선언한 배열에 추가하였습니다. (ArrayList 이용)
- Animal 형으로 선언한 배열에 추가되는 요소의 자료형은 묵시적 형 변환에 의해서 모두 Animal 형으로 변환됩니다.
- 이때 배열의 요소들을 통해서 호출할 수 있는 메서드는 당연스럽게도 Animal 클래스에 선언된 메서드들 뿐입니다.
- 향상된 for 문을 사용하여 모든 배열 요소를 하나씩 꺼내 move() 메서드를 호출하면 가상 메서드에 의하여 각 인스턴스들에서 재정의된 메서드가 호출됩니다.
- 그런데, 각 클래스에서 제공하는 readBook(), hunting(), flying() 메서드는 현재 배열의 요소가 모두 Animal 형이므로 사용할 수 없습니다.
- 다시 말해 자료형이 Animal 형인 상태에서는 Human 클래스가 제공하는 readBook( ) 메서드를 호출할 수 없습니다.
- 각각의 클래스에 선언된 readBook( ), hunting( ), flying( ) 을 호출하기 위해서는 다시 원래 자료형으로 다운 캐스팅되어야 합니다.
- instanceof 를 활용하여 실제 인스턴스 형을 살펴본 후에 다운 캐스팅을 하면 오류를 방지하면서 각 클래스에 있는 메서드를 호출할 수 있습니다.
'[그린컴퓨터] Server > JAVA(객체 지향 프로그래밍)' 카테고리의 다른 글
| 템플릿 메서드 { 추상 클래스와 템플릿 메서드, 템플릿 메서드의 역할, final } (0) | 2023.06.01 |
|---|---|
| 추상 클래스 { 추상 클래스란, 추상 클래스 구현하기, 추상 클래스를 만드는 이유 } (0) | 2023.05.31 |
| 다형성 활용하기 { 배열과 다형성, 배열과 다형성 활용하기, 상속은 언제 사용할까 } (0) | 2023.05.31 |
| 다형성 { 다형성이란, 다형성의 장점 } (0) | 2023.05.31 |
| 메서드 오버라이딩 { 상위 클래스 메서드 재정의하기, VIP 고객 클래스의 제품 가격 계산 메서드 재정의하기, 묵시적 클래스 형 변환과 메서드 재정의, 가상 메서드 } (0) | 2023.05.30 |