Java에서는 자식 객체를 부모 타입으로 참조하는 업캐스팅을 통해 다형성을 사용할 수 있다.
하지만 이때 참조 변수의 타입이 '부모'이기 때문에 컴파일러는 부모 클래스에 정의된 멤버만 접근 가능하다.
즉, 자식 클래스에만 있는 메서드를 호출하려고 하면 컴파일 에러가 뜬다.
class Parent {
int x = 5;
Parent() {
System.out.println("Parent 생성자 호출");
}
}
class Child extends Parent {
int x = 10;
Child() {
System.out.println("Child 생성자 호출");
}
int getX() {
return this.x;
}
}
class Main {
public static void main(String[] args) {
Parent p = new Child();
System.out.println(p.getX());
}
}
이렇게 하면 실행이 안 된다.
똑똑한 IntellJ가 실행하기도 전에 경고를 띄워준다.

그걸 무시하고 실행하려고 해도 당연히 컴파일 에러가 뜬다.
p는 Parent 타입이므로,
Parent 클래스에 정의된 멤버만 사용할 수 있다.
이걸 해결하려면 부모 클래스에 메서드 선언만 있어도 된다.
그렇게 하면 Child 클래스에서 오버라이딩한 것이 되니까 부모 클래스에서도 getX()를 인식해서 호출할 수 있게 된다.
class Parent {
int x = 5;
Parent() {
System.out.println("Parent 생성자 호출");
}
int getX() {
return -1;
};
}

그게 아니라면 출력할 때 다운 캐스팅을 사용하면 된다.
class Main {
public static void main(String[] args) {
Parent p = new Child();
System.out.println(((Child) p).getX());
}
}

단, 이 경우 실제로 p가 Child 객체일 때만 가능하다.
그렇지 않으면 ClassCastException이 발생한다.
그리고 (Child) 부분에 이렇게 노란색 경고줄이 뜬다.

이번에도 똑똑한 IntelliJ가 "너 왜 그런 쓸데없는 짓을 하냐. 그럴 거면 그냥 참조 변수를 Child 타입으로 만들어서 써라.."라고 하는 것이다.
맞는 말이다..
이렇게 다운캐스팅은 거의 안 쓰는 방식이고 위험한 방식이다.
그러니 그냥 Child C = new Child(); 이렇게 사용하는 것이 낫다!