Der folgende Code wird kompiliert und erfolgreich ohne Ausnahme ausgeführt
%Vor% sollte nicht die Zeile ArrayList<SuperSample> ssList = (ArrayList<SuperSample>)o;
eine ClassCastException
erzeugen?
während der folgende Code einen Fehler beim Kompilieren-Zeitfehler erzeugt, um Heap-Verschmutzungen zu vermeiden, sollte der oben erwähnte Code nicht eine ähnliche Vorbeugung zur Laufzeit enthalten?
%Vor%BEARBEITEN:
Wenn Type Erasure der Grund dafür ist, sollten nicht zusätzliche Mechanismen vorhanden sein, die verhindern, dass ein ungültiges Objekt zur Liste hinzugefügt wird? zum Beispiel
%Vor%dann warum
%Vor%ist nicht gemacht, um eine Ausnahme zu werfen?
In Ihrem Codebeispiel
%Vor%Sollte nicht die letzte Zeile ein
ClassCastException
erzeugen?
Nein. Diese Ausnahme wird von der JVM ausgelöst, wenn inkompatible Typen zur Laufzeit erkannt werden. Wie andere bereits festgestellt haben, liegt dies an löschung von generischen Typen. Das heißt, generische Typen sind nur dem Compiler bekannt. Auf der JVM-Ebene sind die Variablen alle vom Typ ArrayList
(die Generika wurden gelöscht), daher gibt es zur Laufzeit kein ClassCastException
.
Nebenbei: Statt einer lokalen Zwischenvariable vom Typ Object
zuzuweisen, besteht eine prägnantere Möglichkeit für diese Zuweisung darin, rough zu durchlaufen:
wobei ein "roher" Typ die gelöschte Version eines generischen Typs ist.
Sollte es keine zusätzlichen Mechanismen geben, die verhindern, dass ein ungültiges Objekt zur Liste hinzugefügt wird?
Ja, da sind. Der erste Mechanismus ist die Kompilierzeitprüfung. In Ihrer eigenen Antwort haben Sie den richtigen Ort in der Java-Sprachspezifikation gefunden, in dem Überlastung , was der Begriff für ein ungültiges Objekt ist in der Liste auftreten. Das Geldzitat aus diesem Abschnitt, ganz unten, ist
Wenn keine Operation ausgeführt wird, für die eine ungeprüfte Kompilierungswarnung ausgegeben werden muss, und keine unsicheren Aliasbefehle für Arrayvariablen mit nicht-veränderbaren Elementtypen auftreten, kann keine Heap-Verunreinigung auftreten.
Der gesuchte Mechanismus befindet sich also im Compiler und der Compiler benachrichtigt Sie über Kompilierungswarnungen. Sie haben diesen Mechanismus jedoch mithilfe der Annotation @SuppressWarnings
deaktiviert. Wenn Sie diese Anmerkung entfernen würden, erhalten Sie eine Compiler-Warnung in der betreffenden Zeile. Wenn Sie die Verschmutzung durch Heaps unbedingt vermeiden möchten, verwenden Sie nicht @SuppressWarnings
und fügen Sie der Befehlszeile -Xlint:unchecked -Werror
die Optionen javac
hinzu.
Der zweite Mechanismus ist die Laufzeitprüfung, die die Verwendung eines der geprüften Wrapper erfordert. Ersetzen Sie die Initialisierung von sList
durch Folgendes:
Dadurch wird ClassCastException
an dem Punkt ausgelöst, an dem der Liste ein SuperSample
hinzugefügt wurde.
Nein, zur Laufzeit sollten beide Listen nicht den gleichen ArrayList-Typ haben. Dies wird löschen genannt. Generische Parameter sind nicht Teil der kompilierten Klasse, sie werden alle während der Kompilierung gelöscht. Aus Sicht von JVM entspricht Ihr Code:
%Vor%Grundsätzlich vereinfachen Generika die Entwicklung nur, indem sie Kompilierzeitfehler und -warnungen erzeugen, aber sie beeinflussen die Ausführung überhaupt nicht.
BEARBEITEN:
Nun, das Basiskonzept dahinter ist Readable Type . Ich empfehle dringend, dieses Handbuch zu lesen:
Ein verifizierbarer Typ ist ein Typ, dessen Typinformationen vollständig verfügbar sind zur Laufzeit. Dies beinhaltet Primitive, nicht-generische Typen, Rohtypen, und Aufrufe von ungebundenen Platzhaltern.
Nicht umformbare Typen sind Typen, bei denen Informationen entfernt wurden Kompilierzeit nach Typ löschen
Um kurz zu sein: Arrays sind ratifizierbar und generische Collections nicht. Wenn Sie also etw im Array speichern, wird type von JVM überprüft, da der Typ des Arrays zur Laufzeit vorhanden ist. Array stellt nur ein Stück Erinnerung dar, während Sammlung eine gewöhnliche Klasse ist, die irgendeine Art von Implementierung haben kann. Zum Beispiel kann es Daten in db oder auf der Festplatte unter der Haube speichern. Wenn Sie tiefer gehen möchten, empfehle ich, Java Generics and Collections zu lesen.
Der Schlüssel hier, um Ihre Frage zu beantworten, ist Type Erasure in Java
Sie haben eine Warnung zur Kompilierungszeit für Ihren ersten Fall und nicht in der Sekunde wegen Ihrer Indirektion durch ein Objekt, die den Compiler daran hindert, Sie zu warnen (ich sList
ssList
und o
alle ArrayList
Ich denke, dass dies ClassCastException wegen Rückwärtskompatibilitätsproblem in Java nicht erzeugen kann.
Generische Informationen sind nicht im Bytecode enthalten (der Compiler erhält während der Kompilierung RIDs).
Stellen Sie sich ein Szenario vor, dass Sie in Ihrem Projekt einen alten Legacy-Code (eine alte Bibliothek, die in Java 1.4 geschrieben wurde) verwenden und die generische Liste an eine Methode in diesem Legacy-Code übergeben. Sie können dies tun.
Rechtzeitig vor Generics wurde Legacy-Code erlaubt, alles (außer Primitive) in eine Sammlung zu legen. Daher kann dieser Legacy-Code keine ClassCastException erhalten, auch wenn er versucht, String in die Liste & lt; Integer & gt; Aus der Sicht des Legacy-Codes ist es nur List.
Dieses seltsame Verhalten ist also eine Folge des Löschens von Typen und der Rückwärtskompatibilität in Java.
BEARBEITEN:
Sie erhalten ArrayStoreException für Arrays, weil die JVM zur Laufzeit den Typ von Arrays kennt und Sie keine Ausnahme für Collections erhalten, weil Type Erasure und dieses Abwärtskompatibilitätsproblem JVM den Typ der Sammlung zur Laufzeit nicht kennt.
Sie können zu diesem Thema im Buch "SCJP Sun® Certified Programmer für Java ™ 6 Study Guide" in Kapitel 7 "Generics and Collections"
nachlesenAus der JLS (4.12. 2)
Es ist möglich, dass sich eine Variable eines parametrisierten Typs auf ein Objekt bezieht, das nicht definiert ist dieses parametrisierten Typs. Diese Situation wird als Haufenverschmutzung bezeichnet. Diese Situation kann nur auftreten, wenn das Programm eine Operation ausführt, die einen Anstieg verursachen würde zu einer ungeprüften Warnung bei der Kompilierung.
Zum Beispiel der Code:
%Vor% führt zu einer ungeprüften Warnung, weil es nicht möglich ist,
Zeit (innerhalb der Grenzen der Kompilierzeit Typprüfregeln) oder zur Laufzeit, ob
Die Variable l bezieht sich tatsächlich auf List<String>
.
Wenn der obige Code ausgeführt wird, tritt Heap-Verschmutzung auf, wie die Variable ls, die zu a erklärt wird
List<String>
, bezieht sich auf einen Wert, der nicht tatsächlich ein List<String>
ist.
Das Problem kann zur Laufzeit nicht identifiziert werden, da Typvariablen nicht verdinglicht werden.
und somit enthalten Instanzen zur Laufzeit keine Informationen über den tatsächlichen Typ
Parameter verwendet, um sie zu erstellen.
Tags und Links java generics classcastexception