public class Animal {
public void eat() {}
}
public class Dog extends Animal {
public void eat() {}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = (Dog) animal;
}
}
Die Zuweisung Dog dog = (Dog) animal;
generiert keinen Kompilierungsfehler, aber zur Laufzeit generiert sie einen ClassCastException
. Warum kann der Compiler diesen Fehler nicht erkennen?
java
casting
classcastexception
Saravanan
quelle
quelle
Antworten:
Wenn Sie eine Besetzung verwenden, sagen Sie dem Compiler im Wesentlichen: "Vertrauen Sie mir. Ich bin ein Profi, ich weiß, was ich tue, und ich weiß, dass ich Ihnen nicht garantieren kann, dass diese
animal
Variable definitiv ist werde ein Hund sein. "Da das Tier eigentlich kein Hund ist (es ist ein Tier, das Sie tun könnten
Animal animal = new Dog();
und es wäre ein Hund), löst die VM zur Laufzeit eine Ausnahme aus, weil Sie dieses Vertrauen verletzt haben (Sie haben dem Compiler gesagt, dass alles in Ordnung ist und es ist nicht!)Der Compiler ist ein bisschen schlauer als nur blind alles zu akzeptieren. Wenn Sie versuchen, Objekte in verschiedenen Vererbungshierarchien umzuwandeln (z. B. einen Hund in einen String umwandeln), wirft der Compiler ihn zurück, weil er weiß, dass dies möglicherweise niemals funktionieren könnte.
Da Sie den Compiler im Wesentlichen nur daran hindern, sich zu beschweren, ist es bei jedem Casting wichtig zu überprüfen, ob Sie keine verursachen,
ClassCastException
indem Sieinstanceof
eine if-Anweisung (oder etwas in diesem Sinne) verwenden.quelle
Dog
sich aus verlängernAnimal
!Denn theoretisch
Animal animal
kann ein Hund sein:Im Allgemeinen ist Downcasting keine gute Idee. Sie sollten es vermeiden. Wenn Sie es verwenden, fügen Sie besser einen Scheck hinzu:
quelle
Um diese Art von ClassCastException zu vermeiden, haben Sie:
Sie können in B einen Konstruktor definieren, der ein Objekt von A nimmt. Auf diese Weise können wir die "Umwandlung" durchführen, z.
quelle
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 einDog
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 .Wenn die JVM zur Laufzeit herausfindet, dass sich die
Dog d
tatsächlich aufAnimal
einDog
Objekt bezieht und nicht auf ein Objekt, das sie sagt. Hey ... du hast den Compiler angelogen und ein großes Fett geworfenClassCastException
.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 vorliegtdog
.Betrachten Sie das folgende Code-Snipet:
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
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.
quelle
Der Code generiert einen Kompilierungsfehler, da Ihr Instanztyp ein Tier ist:
Downcasting ist in Java aus mehreren Gründen nicht zulässig. Siehe hier für Details.
quelle
Wie erklärt ist es nicht möglich. Wenn Sie eine Methode der Unterklasse verwenden möchten, prüfen Sie die Möglichkeit, die Methode zur Oberklasse hinzuzufügen (möglicherweise leer), und rufen Sie von den Unterklassen auf, um dank Polymorphismus das gewünschte Verhalten (Unterklasse) zu erhalten. Wenn Sie also d.method () aufrufen, ist der Aufruf ohne Casting erfolgreich. Falls das Objekt jedoch kein Hund ist, gibt es kein Problem
quelle
So entwickeln Sie die Antwort von @Caumons:
Schauen Sie sich nun diese Lösung an.
Jetzt testen wir die Anwendung:
Und hier ist das Ergebnis:
Jetzt können Sie der Vaterklasse ganz einfach neue Felder hinzufügen, ohne sich Sorgen machen zu müssen, dass die Codes Ihrer Kinder nicht mehr funktionieren.
quelle