묵시적으로 상위 클래스 형변환된 인스턴스가 원래 자료형(하위클래스)으로 변환되어야 할 때 다운캐스팅이라고 합니다.
아래의 예와 같이 묵시적으로 이루어진 상위클래스와는 다르게 하위 클래스로의 형 변환은 명시적으로 되어야 합니다.
예) Customer vc = new VIPCustomer(); //묵시적
VIPCustomer vCustomer = (VIPCustomer)vc;//명시적
//1번
//Human클래스
public void readBook() {
System.out.println("사람이 책을 읽습니다");
}
//Tiger클래스
public void move() {
System.out.println("호랑이가 네발로 뜁니다");
}
//Eagle 클래스
public void flying() {
System.out.println("독수리가 두날개를 쭉뻗고 납니다");
}
//2번
Animal hAnimal = new Human();
Animal tAnimal = new Tiger();
Animal eAnimal = new Human();
Human human = (Human)hAnimal;
human.readBook(); //사람이 책을 읽습니다
//3번
//Eagle eagle = (Eagle)hAnimal; //오류
//4번
if(hAnimal instanceof Eagle) {
Eagle eagle = (Eagle)hAnimal; //아무것도알이어남
}
if(hAnimal instanceof Human) {
Human human = (Human)hAnimal;
human.readBook(); 사람이 책을 읽습니다
}
1번 : Animal 클래스에서 Human, Tiger, Eagle 클래스에 각각 readbood, hunting, flying 메서드를 추가합니다.
2번: 위에서 작성한 메서드를 사용하기 위해 생성된 인스턴스 중 hAnimal을 다운캐스팅하기 위해 Human 변수를 생성하고 그후 (Human)을 캐스팅해서 hAnimal을 Animal에서 Human으로 다운캐스팅하고 Human의 메서드인 .readbook을 사용헤보니 출력이 잘되는 것을 확인할 수 있습니다.
3번 : 이번엔 Human 클래스인 hAnimal에 Egale로 다운캐스팅을 하고 실행을하면 오류가 발생합니다\
4번: 3번과 같은 오류를 방지하기 위해 if문에 instanceof를 사용해 해당 인스턴스가 Eagle이 맞으면 다운캐스팅을 하고 아니면 아무일도 하지 않도록 했더니 flase가 반환되 아무일도 일어나지 않았습니다. 이후 Human클래스로 바꾸어서 다시 작성하니 readBook메서드가 실행되는 것을 확인할 수 있습니다.
이처럼 instanceof는 어떤 인스턴스가 해당 클래스가 맞는지 유효성 검사를 해주어 복잡한 코드에서 에러가 나는 것을 방지해주는 역할을 합니다.
//AnimalMoving 클래스
public void testDeownCasting(ArrayList<Animal> list) {
//1번
for(int i = 0 ; i <list.size(); i++) {
Animal ani = list.get(i);
//2번
if(ani instanceof Human ) {
Human human = (Human)ani;
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("error");
}
}
}
public static void main(String[] args) {
//3번
Animal hAnimal = new Human();
Animal tAnimal = new Tiger();
Animal eAnimal = new Human();
ArrayList<Animal> animalList = new ArrayList<Animal>();
animalList.add(hAnimal);
animalList.add(tAnimal);
animalList.add(eAnimal);
AnimalMove test = new AnimalMove();
//4번
test.testDeownCasting(animalList);
/*사람이 책을 읽습니다
호랑이가 사냥을 합니다
사람이 책을 읽습니다*/
테스트를 위해 AnimalMoving 클래스에 testDownCasting 메서드를 작성하고 매개변수로 Animal자료형의 ArryList를 입력받습니다
1번 : 반복문을 통해 list에 있는 값을 ani변수에 하나씩 대입합니다.
2번 : if문을 통해 ani의 클래스가 Human, Eagle, Tiger 중에 어떤 클래스인지 찾고 해당 클래스가 맞다면 다운캐스팅 한 이후 각자의 메서드를 사용하도록 합니다.
3번 : main 메서드로 돌아와 생성된 인스턴스들을 ArrayList에 넣고 사용하기 testDownCasting메서드를 사용하기 위해 AnimalMove인스턴스를 생성합니다.
4번: testDownCasting()메서드를 사용하고 매개변수로 animalList를 넣고 실행하니 아래의 결과값이 출력되는 것을 확인 할 수 있습니다.
이처럼 instanceof를 활용하여 에러가 나는 것을 방지하면서 다운캐스팅을 하는 방법을 배웠습니다.
정리 해보면 상위 클래스에서 오버라이딩을 해서 여러 하위 클래스에서 동시에 사용할 수 있는 메서드의 경우는 오버라이딩을 해서 사용하는게 효율적이지만 그렇지 않은 개별적인 메서드의 경우는 안전하게 instanceof를 사용해서 다운캐스팅을 통해 사용하는게 좋다는걸 알 수 있습니다.