모든지 기록하자!

[Java] 다운 캐스팅과 instanceof 본문

Java

[Java] 다운 캐스팅과 instanceof

홍크 2021. 5. 18. 00:08
728x90

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

다운 캐스팅(down casting) 이라고 한다.

instanceof

상속관계를 보면 모든 인간은 동물이지만 모든 동물이 인간은 아니다.

따라서 다운 캐스팅을 하기 전에 상위 클래스로 형 변환된 인스턴스의 원래 자료형을 확인해야

변환할 때 오류를 막을 수 있다. 이것을 확인하는 예약어가 ' instanceof ' 다.

Animal hAnimal = new Human();
if(hAnimal instanceof Human     // hAnimal 인스턴스의 자료형이 Human형이라면
	Human human = (Human)hAnimal;	// 인스턴스 hAnimal을 Human형으로 다운캐스팅
}

참조 변수 hAnimal은 원래 Human형으로 생성되었지만 Animal형으로 형 변환되었다.

instanceof 예약어는 왼쪽에 있는 변수의 원래 인스턴스형이 오른쪽 클래스 자료형인가를 확인한다.

instanceof의 반환 값이 true면 다운 캐스팅을 한다. 이때 Human human = (Human)hAnimal; 과 같이

명시적으로 자료형을 써줘야 한다. 상위 클래스로는 묵시형으로 형 변환이 되지만 하위 클래스로

형 변환을 할 때는 명시적으로 해야한다. 

 

원래 자료형이 Human형이 아닌 경우

Animal ani = new Tiger();
Human h = (Human)ani;

이렇게 코딩해도 컴파일 오류는 나지 않는다. 이유는? Tiger 인스턴스는 Animal형으로 자동 형 변환이 된다.

변수 h의 자료형 Human과 강제 형 변환되는 ani의 (Human) 형이 동일하기 때문에 컴파일 오류는 나지 않는다.

이 코드를 실행하면 실행 오류가 발생한다.

 

아래 예제로 확인해보자

import java.util.ArrayList;

class Animal{		// 상위 클래스 Animal
	public void move() {  
		System.out.println("동물이 움직입니다.");
	}
}
class Human extends Animal{ // Animal을 상속받은
	public void move() {	// Human 클래스
		System.out.println("사람이 두발로 걷습니다.");
	}
	public void readBook() {
		System.out.println("사람이 책을 읽습니다.");
	}
}
class Tiger extends Animal{ // Animal을 상속받은
	public void move() {	// Tiger 클래스
		System.out.println("호랑이가 네발로 뜁니다.");
	}
	public void hunting() {
		System.out.println("호랑이가 사냥을 합니다.");
}
}
class Eagle extends Animal{ // Animal을 상속받은
	public void move() {	// Eagle 클래스
		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 test = new AnimalTest();
		test.addAnimal();
		System.out.println("===원래 형으로 다운 캐스팅===");
		test.testCasting();
	}
	public void addAnimal() {
		aniList.add(new Human()); // ArrayList에 추가되면서
		aniList.add(new Tiger());    // Animal형으로 형 변환
		aniList.add(new Eagle());
		
		for(Animal ani: aniList) { // 배열 요소를 Animal형으로 꺼내서 
			ani.move();	// move()를 호출하면 재정의된 함수가 호출된다.
		}
	}
	public void testCasting() {
			
		for(int i=0; i<aniList.size(); i++) { // 모든 배열 요소를 하나씩 돌면서
			Animal ani = aniList.get(i); 	   // Animal형으로 가져온다.
			if(ani instanceof Human) { // animal이 Human인지 확인
				Human human = (Human)ani; // Human이면 Human형으로 다운 캐스팅한다.
				human.readBook();
			}
			else if(ani instanceof Tiger) { 
				Tiger tiger = (Tiger)ani;
				tiger.hunting();
			}
			else if(ani instanceof Eagle) { 
				Eagle eagle = (Eagle)ani;
				eagle.flying();
		}
			else {
				System.out.println("지원되지 않는 기능입니다.");
			}
		}
	}
}

배열의 요소가 Animal형이므로 각 클래스에서 제공하는 readBook(), hunting(), flying() 메서드를

사용할 수 없다.  자료형이 Animal인 상태이기 때문이다. readBook(), hunting(), flying()을 호출하려면

원래 자료형으로 다운 캐스팅되어야 한다.

 

출력결과

 

728x90
Comments