Wenn der Compiler auf B b = (B)a;
stößt, weiß er ohne Zweifel, dass a
vom Typ A
ist und nicht legal in B
umgewandelt wird.
Wenn der Compiler jedoch B b1 = (B)i;
kompiliert, weiß er nur, dass i
ein Objekt ist, das I
implementiert - es könnte sein:
und die Umwandlung in B
könnte legal sein, sodass sie nicht als Fehler behandelt werden kann.
Dies ist wirklich nur eine Re-Aussage von Jaffreys Antwort mit etwas mehr Erzählung.
es ist eine Verengung Referenz Konvertierung .. nach Java-Spezifikation $ 5.1.5 ist erlaubt.
Von jedem Schnittstellentyp J zu jeder nicht parametrisierten Klassenart C, die nicht endgültig ist.
Diese Konvertierung zeigt keine Fehler bei der Kompilierung an, wird jedoch zur Laufzeit überprüft. Es würde ein ClassCastException
nach $ 5.5.3 werfen wenn die Schnittstelle mit einer richtigen Klasse initialisiert wurde, die nicht mit B. zusammenhängt, aber jetzt nicht wirft, da die Schnittstelle null ist und wir wissen
Ein Wert des Nulltyps (der NULL-Verweis ist der einzige derartige Wert) kann einem beliebigen Referenztyp zugewiesen werden, was zu einem NULL-Verweis dieses Typs führt.
NB. .. ich wurde nicht über all die oben genannten Begriffe anerkannt ... Ich fühle nur Interesse zu suchen, nachdem ich die Frage gesehen habe. also korrigiere mich bitte, wenn mein Befund falsch ist oder ich etwas falsch verstanden habe
Ich glaube, dass den anderen Antworten ein wichtiges Detail fehlt: Es ist möglich, weil der Compiler einfach nicht in Schnittstellen schaut.
Die Argumente, die dies erklären sollen, wurden als
formuliertkönnte
seinclass B2 extends B implements I
und
Der Compiler weiß hier, dass
A
undB
nicht verwandt sind
Dies ist sehr wahr, aber es erklärt nicht, warum der Compiler weiß, dass diese beiden Klassen nicht verwandt sind und nicht warum er nicht wissen kann, wenn ein Schnittstelle wurde implementiert.
Am Ende sollten diese beiden Situationen ziemlich ähnlich sein: Wenn es zur Kompilierzeit prüfen kann, ob zwei Klassen eine Beziehung haben, dann sollte es in der Lage sein, zur Kompilierzeit zu überprüfen, ob eine Schnittstelle in dieser Klasse implementiert ist Diese Situationen stehen zur Kompilierungszeit zur Verfügung.
Daher stimme ich dem Kommentar von Hot Licks in das Duplikat :
Weil. Auch wenn Cat Möbel nicht direkt umsetzen darf, mag irgendeine Oberklasse von Cat. Und der Compiler beschließt, sich nicht in solche hässlichen Details zu vertiefen, da die Regeln für Schnittstellen ziemlich kompliziert sind. (Danke, Sun.) Und es gibt keine allgemeine Regel, die den Compiler auffordert, eine unvermeidliche Laufzeitausnahme zu erkennen (z. B. Division durch Null) - es ist eher ein "Service", den es bereitstellt.
Die Überprüfung der Schnittstelle zur Kompilierzeit sollte möglich sein, sie wird vom Compiler aus Gründen, die wir nur erraten können, nicht gemacht. die in den Kommentaren besprochen werden .
Nach einer ausführlichen (und sehr interessanten) Diskussion in den Kommentaren glaube ich, dass dies geklärt ist.
Es ist einfach und billig zu überprüfen, ob zwei Klassen eine Beziehung haben, Sie schauen sich beide Hierarchien an. Schnittstellen erfordern andererseits Kenntnisse über alle Klassen und Schnittstellen im Projekt (einschließlich externer Ressourcen wie Bibliotheken), um festzustellen, ob eine Beziehung zwischen der Schnittstelle und der Klasse besteht.
Dies führt mich zu der Schlussfolgerung, dass es zwar theoretisch möglich ist, aber nicht machbar ist, weil es zwei Dinge erfordern würde:
Hier finden Sie einige gute Informationen zu Upcasting und Downcasting. Ссылка
Da jede Klasse von Object erbt, können Sie immer zu einem anderen Objekt (B)(Object)a
springen und zu einem anderen Objekt herabstufen. Nicht dass das eine gute Idee ist, aber es ist gültig. Wenn Sie tatsächlich A instanziiert hätten, würden Sie eine Laufzeitausnahme java.lang.ClassCastException
erhalten, als wären Sie instanziiert und eine Instanz von I i = new I(){}