Michael Berry의 답변을 정교화합니다.
Dog d = (Dog)Animal; //Compiles but fails at runtime
여기서는 컴파일러에게 "신뢰하십시오. d
실제로 Dog
객체를 참조하고 있다는 것을 알고 있습니다"라고 말하는 것은 아닙니다.
다운 캐스트를 수행 할 때 컴파일러가 우리를 신뢰해야한다는 것을 기억하십시오 .
컴파일러는 선언 된 참조 유형에 대해서만 알고 있습니다. 런타임시 JVM은 오브젝트가 실제로 무엇인지 알고 있습니다.
따라서 런타임시 JVM Dog d
이 실제로 객체가 Animal
아닌 Dog
객체를 참조 하고 있음을 알아 냈습니다 . 이봐 ... 당신은 컴파일러에 거짓말을하고 큰 지방을 던졌습니다 ClassCastException
.
따라서 다운 캐스팅하는 경우 instanceof
테스트를 사용 하여 실수를 피해야합니다.
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}
이제 질문이 떠 오릅니다. 지옥 컴파일러가 다운 캐스트를 허용하는 이유는 무엇 java.lang.ClassCastException
입니까?
대답은 컴파일러가 할 수있는 모든 것이 두 유형이 동일한 상속 트리에 있는지 확인하는 것입니다. 따라서 다운 캐스트 전에 올 수있는 코드에 따라 animal
유형이 가능합니다 dog
.
컴파일러는 런타임에 작동 할 수있는 것을 허용해야합니다.
다음 코드 스 니펫을 고려하십시오.
public static void main(String[] args)
{
Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog
Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :)
d.eat();
}
private static Animal getMeAnAnimal()
{
Animal animal = new Dog();
return animal;
}
그러나 컴파일러가 캐스트가 가능하지 않다고 확신하면 컴파일이 실패합니다. IE 상속 계층이 다른 객체를 캐스팅하려고하면
String s = (String)d; // ERROR : cannot cast for Dog to String
다운 캐스팅과 달리 업 캐스팅은 암시 적으로 작동합니다. 업 캐스팅 할 때 다운 캐스팅과 반대로 호출 할 수있는 메서드 수를 암시 적으로 제한하므로 나중에보다 구체적인 메서드를 호출 할 수 있습니다.
Dog d = new Dog();
Animal animal1 = d; // Works fine with no explicit cast
Animal animal2 = (Animal) d; // Works fine with n explicit cast
동물이 할 수 있다고 주장하는 개 IS-A 동물, 개가 할 수 있다고 말하면 위의 두 가지 모두 예외없이 잘 작동합니다. 그러나 그것은 사실이 아닙니다.