Ausarbeitung der Antwort von Michael Berry.
Dog d = (Dog)Animal; //Compiles but fails at runtime
Hier sagen Sie dem Compiler "Vertrau mir. Ich weiß, dass er d
sich wirklich auf ein Dog
Objekt bezieht ", obwohl dies nicht der Fall ist.
Denken Sie daran, dass der Compiler gezwungen ist, uns zu vertrauen, wenn wir einen Downcast ausführen .
Der Compiler kennt nur den deklarierten Referenztyp. Die JVM zur Laufzeit weiß, was das Objekt wirklich ist.
Wenn die JVM zur Laufzeit herausfindet, dass sich die Dog d
tatsächlich auf Animal
ein Dog
Objekt bezieht und nicht auf ein Objekt, das sie sagt. Hey ... du hast den Compiler angelogen und ein großes Fett geworfen ClassCastException
.
Wenn Sie also niedergeschlagen sind, sollten Sie einen instanceof
Test verwenden, um ein Versagen zu vermeiden.
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}
Jetzt kommt uns eine Frage in den Sinn. Warum erlaubt der Höllen-Compiler den Downcast, wenn er irgendwann einen werfen wird java.lang.ClassCastException
?
Die Antwort lautet, dass der Compiler lediglich überprüfen kann, ob sich die beiden Typen im selben Vererbungsbaum befinden. Je nachdem, welcher Code vor dem Downcast gekommen sein könnte, ist es also möglich, dass dieser animal
Typ vorliegt dog
.
Der Compiler muss zulassen, dass Dinge zur Laufzeit funktionieren.
Betrachten Sie das folgende Code-Snipet:
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;
}
Wenn der Compiler jedoch sicher ist, dass die Umwandlung nicht funktionieren würde, schlägt die Kompilierung fehl. IE Wenn Sie versuchen, Objekte in verschiedene Vererbungshierarchien umzuwandeln
String s = (String)d; // ERROR : cannot cast for Dog to String
Im Gegensatz zu Downcasting funktioniert Upcasting implizit, da Sie beim Upcasting implizit die Anzahl der Methoden einschränken, die Sie aufrufen können, im Gegensatz zum Downcasting, was impliziert, dass Sie später möglicherweise eine spezifischere Methode aufrufen möchten.
Dog d = new Dog();
Animal animal1 = d; // Works fine with no explicit cast
Animal animal2 = (Animal) d; // Works fine with n explicit cast
Beide oben genannten Upcasts funktionieren ausnahmslos einwandfrei, da ein Hund IS-A Animal ist, was ein Tier kann, was ein Hund kann. Aber es ist nicht wahr umgekehrt.