Iterierte parametrisierte Liste (nach unformatierter Listentyp-Zuweisung)

8

Sprache: Java
Compiler-Version: 1.6

Im folgenden Code versuche ich Folgendes zu tun:

  1. Erstelle ein List<String>
  2. füge ein String hinzu
  3. weisen Sie List<String> dem rohen List zu
  4. Erstelle ein List<Integer>
  5. weisen Sie den rohen List zu List<Integer> zu
  6. füge ein Integer hinzu
  7. ruft den Wert mit get() @ indexes 1 & amp; 2 und drucken sie.

Alle Anweisungen werden kompiliert (mit Warnungen) und laufen gut.

Aber wenn ich versuche, die List<Integer> mit einer for Schleife zu durchlaufen, erhalte ich ClassCastException . Ich frage mich nur, warum es mir erlaubt, list.get() method zu verwenden, aber nicht zu erlauben, dass ich darüber iteriere?

Ausgabe: (wenn ich mit nicht kommentierter for-Schleife laufe) abcd 200

%Vor%

Hier ist mein Code

%Vor%     
pulikarthi 09.09.2012, 15:01
quelle

2 Antworten

5

Ich würde dies als Compilerfehler in javac betrachten. Eine geprüfte Besetzung wird eingefügt. Wir können dies mit javap -c CheckRawTypeAdd sehen, um die Klasse zu disassemblieren (Cast ist 101; beachten Sie, dass ich vor dem Kompilieren einige der nicht benötigten Codezeilen entfernt habe, sodass die Codepunkte variieren können):

%Vor%

Die Java-Sprachspezifikation (14.14. 2) bedeutet, dass dieser Cast auf Object , nicht auf Integer gesetzt sein sollte. Es beginnt mit der Definition der Begriffe über die Grammatik:

%Vor%

In unserem Fall ist also Type Object . Dann geht es weiter, um zu sagen, in was übersetzt wird:

%Vor%

Was hier relevant ist, ist die Auflösung von TargetType . Dies ist auch in der JLS definiert:

  

Wenn Type (in der FormalParameter-Produktion) ein Referenztyp ist, ist TargetType der Typ

As Object ist mit Sicherheit ein Referenztyp, dann ist TargetType Object und der checkedcast sollte also auf Object , nicht auf Integer .

gesetzt sein

Dass dies ein Fehler ist, wird von anderen in diesem Thread weiter belegt, dass dieses Problem nicht auftritt, wenn ecj (Eclipse-Compiler) verwendet wird. Ich verstehe jedoch, dass dies ein Fehler mit niedriger Priorität für das Oracle-Compiler-Team wäre, da Sie Generika missbrauchen müssen, um sie auszuüben. Man würde fast sagen, es ist ein Feature, kein Bug.

Nachverfolgung

Um die endgültige Bestätigung zu geben, dass es sich um einen Fehler handelt, gibt es hier einen bestehenden Fehlerbericht für genau dieses Problem:

Außerdem sollte ich zwei Dinge beachten. Zuerst , die JLS-Referenzen, die ich oben angegeben habe, waren in der letzten JLS, und dieser Abschnitt hat sich tatsächlich für Java 7 geändert (als Antwort auf diesen Fehler!)

Hier ist, was eine verbesserte for-Anweisung in für Java 6 und früher :

%Vor%

Wie Sie sehen können, ist hier no checked cast angegeben. Der Fehler in javac war also nicht, dass es die falsche Besetzung gemacht hat, sondern dass überhaupt eine Besetzung gemacht wurde .

Second , in Java 7 kompiliert javac den Code gemäß der Spezifikation JLS SE 7 (was ich oben zitiert habe). Daher funktioniert der folgende Code:

%Vor%

Mit einer korrekten Umwandlung in CharSequence , nicht in String . Ich habe JDK 6 zuerst kompiliert, nicht JDK 7.

    
Mark Peters 09.09.2012, 15:38
quelle
1

Code

%Vor%

Entspricht etwa so etwas:

%Vor%

Wie Sie sehen können, ist Iterator generisch und setzt daher Werte auf seinen Parametertyp ( Integer unser Fall).

Also macht die Zeile Integer o = it.next(); hinter der Szene folgendes:

Integer o = (Integer)it.next();

Ich denke, dass es jetzt offensichtlich ist, wie die ClassCastException produziert wird. Wirklich, Sie haben es geschafft, einen String-Wert in die Liste einzufügen. Wenn also it.next() die Zeichenkette zurückgibt, schlägt das Casting fehl.

Die Frage "Wie ist es Ihnen gelungen, einen String in die int-Liste einzufügen", bleibt also bestehen. Die Antwort ist, dass Generika die Compilermagie sind. Ihr anderer Name ist Löschungen. Java-Byte-Code enthält keine Informationen über den Listentyp. Es enthält nur Gießen auf Betontyp bei Bedarf. Aus diesem Grund ist es Ihnen gelungen, die parametrisierte Liste der unformatierten Liste zuzuordnen und dann einen Stich hinzuzufügen.

Wie Sie richtig erwähnt haben, haben Sie Warnungen gesehen. Die Schlussfolgerung lautet: "Kompilierungswarnungen nicht ignorieren."

    
AlexR 09.09.2012 15:17
quelle