public class Parent {
public void parentMethod() {
System.out.println("Parent.parentMethod");
}
}
public class Child extends Parent {
public void childMethod() {
System.out.println("Child.childMethod");
}
}
Parent parent = new Parent();
parent.parentMethod();

Child child = new Chiled();
child.childMehtod();

Parent poly = new Child();
poly.parentMethod();

Parent poly = new Child();
poly.childMethod();

poly.childMethod()를 실행하면 먼저 참조값을 통해 인스턴스를 찾는다. 그리고 다음으로 인스턴스 안에서 실행할 타입을 찾는다. 호출자인 poly는 Parent 타입이다. 따라서 Parnet 클래스부터 시작해서 필요한 기능을 찾는다. 그런데 상속 관계는 부모 방향으로 찾아 올라갈 수는 있지만 자식 방향으로 찾아 내려갈 수는 없다. Parent는 부모 타입이고 상위에 부모가 없다. 따
라서 childMethod()를 찾을 수 없으므로 컴파일 오류가 발생한다.

호출하는 타입을 자식인 Child 타입으로 변경하면 인스턴스의 Child에 있는 childMethod()를 호출할 수 있다.

Parent poly = new Child();
Child child = poly; //불가능
Child child = (Child) poly; //가능
Parent poly = new Child();
((Child) poly).childMethod;
메서드를 호출하는 순간만 다운캐스팅 할 수도 있다.
Child child = new Child();
Parent parent1 = child; // 생략 가능
Parent parent2 = (Parent) child;
업캐스팅시에는 문제가 발생하지 않기 때문에 생략이 가능하다
다운캐스팅은 잘못하면 심각한 런타임 오류가 발생할 수 있다.
public class Main {
public static void main(String[] args) {
Parent parent1 = new Child();
Child child1 = (Child) parent1;
child1.childMethod(); //문제없음
Parent parent2 = new Parent();
Child child2 = (Child) parent2; //런타임 오류 - ClassCastException
child2.childMethod(); //실행 불가
}
}


instanceof키워드를 사용해서 미리 타입을 확인하는 것이 좋다.
public class main {
public static void main(String[] args) {
Parent parent = new Child();
System.out.println("parent 호출");
call(parent);
}
private static void call(Parent parent) {
parent.parentMethod();
if(parent instanceof Child) {
System.out.println("Child 인스턴스 맞음");
Child child = (Child) parent;
child.childMethod();
}
}
}
실행 결과
Parent 호출
Child 인스턴스 맞음
Child.childMethod
자바 16부터는 instanceof를 사용하면서 동시에 변수를 선언할 수 있다.
public class Main {
public static void main(String[] args) {
Parent parent = new Child();
System.out.println("parent 호출");
call(parent);
}
private static void call(Parent parent) {
parent.parentMethod();
if(parent instanceof Child child) {
System.out.println("Child 인스턴스 맞음");
child.childMethod();
}
}
}
실행 결과
Parent 호출
Child 인스턴스 맞음
Child.childMethod