다운 캐스팅 : 상위 클래스로 형 변환되었던 하위 클래스를 다시 원래 자료형으로 형 변환하는 것
다운 캐스팅을 하기 전에 상위 클래스로 형 변환된 인스턴스의 원래 자료형을 확인해야 변환할 때 오류를 막을 수 있다.
이를 확인하는 예약어가 instanceof이다.
Animal hAnimal = new Human();
if(hAnimal instanceof Human) { // hAnimal 인스턴스 자료형이 Human형이라면
Human human = (Human)hAnimal; // 인스턴스 hAnimal을 Human형으로 다운캐스팅
}
위처럼 사용이 가능한데, 코드에서 사용한 참조 변수 hAnimal은 원래 Human형으로 생성되었다가, Animal형으로 형 변환되었다.
instanceof 예약어는 왼쪽에 있는 변수의 원래 인스턴스형이 오른쪽 클래스 자료형인가를 확인한다.
hAnimal이 Animal형으로 되어있지만, 원래는 Human형으로 생성된 인스턴스인지 확인하는 것이다.
instanceof의 반환 값이 true이면 다운 캐스팅을 하는데, 이때 Human human = (Human)hAnimal; 문장처럼 명시적으로 자료형을 써주어야 한다.
상위 클래스로는 묵시적으로 형 변환이 되지만, 하위 클래스로 형 변환을 할 때는 명시적으로 해야 하기 때문이다.
만약 여기서 instanceof로 인스턴스형을 확인하지 않으면 오류가 발생할 수 있다.
그렇다면 원래 자료형이 Human형이 아닌 경우를 살펴보자.
Animal ani = new Tiger();
Human h = (Human)ani;
위처럼 코딩하면 Tiger 인스턴스는 Animal형으로 자동 형 변환이 되기 때문에
변수 h의 자료형 Human과 강제 형 변환되는 ani의 (Human) 형이 동일하므로 컴파일 오류는 나지 않는다.
다만 실행하면 실행 오류가 발생한다.
따라서 참조 변수의 원래 인스턴스형을 정확히 확인하고 다운 캐스팅을 해야 안전하며 이때 instanceof를 사용한다.
[실습] instanceof로 원래 인스턴스형 확인 후 다운 캐스팅하기
package polymorphism;
import java.util.ArrayList;
class Animal { // 상위 클래스 Animal
public void move() {
System.out.println("동물이 움직입니다.");
}
}
class Human extends Animal { // Animal을 상속받은 Human 클래스
public void move() {
System.out.println("사람이 두 발로 걷습니다.");
}
public void readBook() {
System.out.println("사람이 책을 읽습니다.");
}
}
class Tiger extends Animal { // Animal을 상속받은 Tiger 클래스
public void move() {
System.out.println("호랑이가 네 발로 뜁니다.");
}
public void hunting() {
System.out.println("호랑이가 사냥을 합니다.");
}
}
class Eagle extends Animal { // Animal을 상속받은 Eagle 클래스
public void move() {
System.out.println("독수리가 하늘을 납니다.");
}
public void flying() {
System.out.println("독수리가 날개를 쭉 펴고 멀리 날아갑니다.");
}
}
public class AnimalTest {
ArrayList<Animal> aniList = new ArrayList<Animal>();
// 배열의 자료형을 Animal로 지정
public static void main(String[] args) {
AnimalTest aTest = new AnimalTest();
aTest.addAnimal();
System.out.println("원래 형으로 다운캐스팅");
aTest.testCasting();
}
public void addAnimal() { // ArrayList에 추가되면서 Animal형으로 형 변환
aniList.add(new Human());
aniList.add(new Tiger());
aniList.add(new Eagle());
for(Animal ani : aniList) { // 배열 요소를 Animal형으로 꺼내 move()를 호출하면
ani.move(); // 재정의된 함수가 호출됨
}
}
public void testCasting() {
for(int i = 0; i < aniList.size(); i++) { // 모든 배열요소를 하나씩 돌면서
Animal ani = aniList.get(i); // Animal 형으로 가져옴
if(ani instanceof Human) { // Human 형이면
Human h = (Human)ani; // Human 형으로 다운 캐스팅
h.readBook();
}
else if(ani instanceof Tiger) {
Tiger t = (Tiger)ani;
t.hunting();
}
else if(ani instanceof Eagle) {
Eagle e = (Eagle)ani;
e.flying();
}
else {
System.out.println("지원되지 않는 형입니다.");
}
}
}
}
'Language > Java' 카테고리의 다른 글
[Java] 추상 클래스 (0) | 2022.12.21 |
---|---|
[Java] 다형성 활용하기 (0) | 2022.12.19 |
[Java] 다형성(polymorphism) (0) | 2022.12.15 |
[Java] 메서드 오버라이딩 (1) | 2022.12.13 |
[Java] 상속에서 클래스 생성과 형 변환 (0) | 2022.11.20 |