본문 바로가기

Language/Java

[Java] 다운 캐스팅과 instanceof

다운 캐스팅 : 상위 클래스로 형 변환되었던 하위 클래스를 다시 원래 자료형으로 형 변환하는 것

다운 캐스팅을 하기 전에 상위 클래스로 형 변환된 인스턴스의 원래 자료형을 확인해야 변환할 때 오류를 막을 수 있다.

이를 확인하는 예약어가 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