Wenn ich versuche, a String
in a java.util.Date
umzuwandeln, fängt der Java-Compiler den Fehler ab. Warum kennzeichnet der Compiler Folgendes nicht als Fehler?
List<String> strList = new ArrayList<>();
Date d = (Date) strList;
Natürlich wirft die JVM a ClassCastException
löst zur Laufzeit eine aus, aber der Compiler kennzeichnet sie nicht.
Das Verhalten ist das gleiche mit javac 1.8.0_212 und 11.0.2.
java
casting
compiler-errors
javac
Mike Woinoski
quelle
quelle
List
.Date d = (Date) new Object();
strList
es sich um eine Instanz einer Klasse handelt, die List implementiert.Antworten:
Die Besetzung ist technisch möglich. Javac kann nicht einfach beweisen, dass dies in Ihrem Fall nicht der Fall ist, und das JLS definiert dies tatsächlich als gültiges Java-Programm. Daher wäre es falsch, einen Fehler zu kennzeichnen.
Dies liegt daran, dass
List
es sich um eine Schnittstelle handelt. Sie könnten also eine Unterklasse von a habenDate
, die tatsächlichList
wieList
hier getarnt implementiert - und dannDate
wäre es vollkommen in Ordnung, sie zu besetzen. Zum Beispiel:Und dann:
Das Erkennen eines solchen Szenarios ist möglicherweise nicht immer möglich, da Laufzeitinformationen erforderlich sind, wenn die Instanz beispielsweise von einer Methode stammt. Und selbst wenn, würde es viel mehr Aufwand für den Compiler erfordern. Der Compiler verhindert nur Casts, die absolut unmöglich sind, da der Klassenbaum überhaupt nicht übereinstimmen kann. Was hier nicht der Fall ist, wie man sieht.
Beachten Sie, dass das JLS erfordert, dass Ihr Code ein gültiges Java-Programm ist. In 5.1.6.1. Zulässige schmale Referenzkonvertierung heißt es:
Also auch wenn der Compiler könnte herausfinden , dass Ihr Fall tatsächlich nachweislich unmöglich ist, darf er keinen Fehler melden, da das JLS ihn als gültiges Java-Programm definiert.
Es darf nur eine Warnung angezeigt werden.
quelle
myDate = (Date) myString
Scheitern führt. Unter Verwendung der JLS-Terminologie versucht die Anweisung, vonS
(theString
) nachT
(theDate
) zu konvertieren . DaS
es sich nicht um einen Schnittstellentyp handelt, gilt die oben angegebene JLS-Bedingung nicht. Wenn Sie beispielsweise versuchen, einen Kalender in ein Datum umzuwandeln, wird ein Compilerfehler angezeigt, obwohl keine der beiden Klassen endgültig ist.Date & List
ist unbewohnbar , ist es nicht genug , um zu beweisen , dass es unbewohnt zur Zeit (es auch in Zukunft sein könnte).Betrachten wir eine Verallgemeinerung Ihres Beispiels:
Dies sind die Hauptgründe, warum
Date d = (Date) strList;
kein Kompilierungsfehler vorliegt.Der intuitive Grund ist, dass der Compiler (im Allgemeinen) den genauen Typ des von diesem Methodenaufruf zurückgegebenen Objekts nicht kennt. Es ist möglich, dass es nicht nur eine Klasse ist, die implementiert
List
, sondern auch eine Unterklasse vonDate
.Der technische Grund ist, dass die Java-Sprachspezifikation die Verengung der Referenzkonvertierung "erlaubt", die dieser Typumwandlung entspricht. Gemäß JLS 5.1.6.1 :
An einer anderen Stelle sagt JLS auch, dass zur Laufzeit eine Ausnahme ausgelöst werden kann ...
Beachten Sie, dass die Bestimmung von JLS 5.1.6.1 ausschließlich auf den deklarierten Typen der beteiligten Variablen und nicht auf den tatsächlichen Laufzeittypen basiert . Im allgemeinen Fall kennt und kann der Compiler die tatsächlichen Laufzeitarten nicht kennen.
Warum kann der Java-Compiler nicht herausfinden, dass die Besetzung nicht funktioniert?
In meinem Beispiel
someMethod
könnte der Aufruf Objekte mit verschiedenen Typen zurückgeben. Selbst wenn der Compiler in der Lage war, den Methodenkörper zu analysieren und den genauen Satz von Typen zu bestimmen, die zurückgegeben werden könnten, kann nichts jemanden daran hindern, ihn zu ändern, um verschiedene Typen zurückzugeben ... nachdem er den Code kompiliert hat, der ihn aufruft. Dies ist der Hauptgrund, warum JLS 5.1.6.1 sagt, was es sagt.In Ihrem Beispiel ein intelligenter Compiler könnte herausfinden , dass die Besetzung nie gelingen kann. Außerdem darf eine Warnung zur Kompilierungszeit ausgegeben werden , um auf das Problem hinzuweisen.
Warum darf ein Smart Compiler nicht sagen, dass dies überhaupt ein Fehler ist?
Weil das JLS sagt, dass dies ein gültiges Programm ist. Zeitraum. Jeder Compiler, der dies als Fehler bezeichnet , ist nicht Java-kompatibel.
Außerdem ist jeder Compiler, der Java-Programme ablehnt, von denen JLS und andere Compiler sagen, dass sie gültig sind, ein Hindernis für die Portabilität von Java-Quellcode.
quelle
5.5.1. Referenztyp Casting:
List<String>
istS
undDate
istT
in deinem Fall.quelle