マイケルベリーによって与えられた答えを詳しく説明します。
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
答えは、コンパイラが実行できるのは、2つのタイプが同じ継承ツリーにあることを確認することだけです。したがって、ダウンキャストの前に発生したコードによっては、タイプがである可能性があり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
犬は動物であり、動物ができること、犬ができることであるため、上記のアップキャストはどちらも例外なく正常に機能します。しかし、それは真実ではありません。