김영한의 자바 강의 내용을 듣고 정리한 내용입니다.
'다양한 형태' 를 의미한다. 즉, 하나의 객체가 다른 타입으로 사용할 수 있는 기능을 말한다.
먼저 이해하고 가야 할 부분으로, 부모 타입의 인스턴스가 메서드를 호출할 때 타입이 부모이기 때문에 부모 메서드를 참조하게 된다. 또한 부모를 상속하고 있는 자식 메서드는 생성되지 않는다. 아래 그림을 보며 이해하자.

부모 인스턴스가 생성된 곳에 부모의 메서드만 존재하는 것을 볼 수 있다. 상속된 자식 인스턴스는 생성되지 않는다.
하지만, 자식 타입으로 자식 인스턴스를 생성하면 아래와 같은 모습이 된다.

위 그림에서 볼 수 있듯이 자식 타입의 인스턴스를 생성하면 부모의 메서드도 생성됨을 알 수 있다. 그리고 메서드는 인스턴스의 타입인 child 타입에 대한 메서드를 먼저 가리키게 된다. 해당 타입의 메서드가 존재하지 않을 때 부모 타입의 메서드를 호출한다.
그런데 만약 부모 타입으로 자식 인스턴스를 참조하게 되면 어떻게 될까?
자식 인스턴스를 참조했기 때문에 자식 메서드도 메모리상 생기게 된다. 하지만 타입은 부모 타입이므로 메서드 호출 시 부모 메서드를 먼저 참조한다. 그림으로 보면 아래와 같다.

위와 같이 부모타입으로 자식을 참조할 수 있지만, 반대로 자식 타입으로 부모를 참조하는 건 안된다.
Child temp2 = new Parent() // 사용 불가, 오직 부모만 자식을 담을 수 있다.
바로 위의 그림처럼 부모 타입으로 자식을 참조하여 인스턴스를 생성했을 때, 만약 자식메서드를 사용하고 싶다면 바로 사용할 수 없다. 부모타입으로 자식타입의 메서드를 호출 할 수 없기 때문이다. 이때 사용하는 것이 다운캐스팅 이다.
'cast' 의 어원은 금속 혹은 다른 물질을 녹여 다른 형태로 만드는 것
Parent temp = new Child(); // 부모 타입으로 자식 인스턴스 생성
temp.childMethod() // 컴파일 오류 -> temp는 부모 타입을 갖고 있기 때문
Child child = (Child) temp; // temp 를 Child 타입으로 다운캐스팅하고 해당 참조값을 Child 타입 변수에 저장
child.childMethod();
이 코드를 그림으로 보자면 아래와 같다.

((Child) temp).childMethod();
public static void main(String[] args) {
Parent parent1 = new Parent();
System.out.println("parent1 호출");
call(parent1);
Parent parent2 = new Child();
System.out.println("parent2 호출");
call(parent2);
}
private static void call(Parent parent) {
parent.parentMethod();
if (parent instanceof Child) {
System.out.println("Child 인스턴스");
Child child = (Child) parent;
child.childMethod();
parent1 호출
Parent.parentMethod
parent2 호출
Parent.parentMethod
Child 인스턴스
Child.childMethod
오버라이딩 된 메서드가 항상 우선권을 가진다!!! (실행의 우선권)
자식 클래스에서 부모의 메서드를 오버라이딩 했다면, 부모 타입의 인스턴스에서 부모 메서드를 호출 했을 때 오버라이딩 된 메서드 있기 때문에 자식 메서드가 실행된다. (해당 경우는 부모타입으로 자식 인스턴스를 참조 했을 때만 가능 -> 그래야 자식 메서드가 메모리상에 생기기 때문)
public class Parent {
public Stirng value = "parent";
public void method() {
System.out.println("Parent.method");
}
}
public class Child extends Parent {
public Stirng value = "child";
@Override
public void method() {
System.out.println("Child.method");
}
}
public class Main() {
public static void main(String[] args) {
// 자식 타입으로 자식 인스턴스 참조
Child child = new Child();
child.method();
// 부모 타입으로 부모 인스턴스 참조
Parent parent = new Parent();
parent.method();
// 부모 타입으로 자식 인스턴스 참조 (다형적 참조)
Parent temp = new Child();
temp.method(); // 메서드 오버라이딩 확인되면, 오버라이딩 된 메서드가 우선권을 가짐