Frage

Unter welchen Umständen kann Classcast im Code auftritt unten:

import java.util.Arrays;
import java.util.List;

public class Generics {

    static List getObjects() {
        return Arrays.asList(1, 2, 3);
    }

    public static void main(String[] args) {
        List<String> list = getObjects();
        for (Object o : list) { // ClassCastException?
            System.out.println(o);
        }
    }
}

Wir hatten einen ähnlichen Fall in einer Produktionsumgebung (schlechte Praxis, ich weiß) und der Kunde ein Protokoll mit Classcast an der Linie mit dem Kommentar versehen, aber ich kann es nicht zu reproduzieren scheint. Irgendwelche Gedanken?

Ich weiß, dass der JVM einen Iterator im Hintergrund erstellt, wenn foreach verwenden, aber es kann ein rohes Iterator in einigen Fällen und ein parametrisierte man in anderen Fällen erstellen?

Aktualisieren : ich auch einen Blick auf den Bytecode hatte erzeugt und auf Windows, mit JDK 1.6.0_21-b07 no checkcast gemacht wurde. Interessant :)

Hier ist die wichtigste Methode:

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #34; //Method getObjects:()Ljava/util/List;
   3:   astore_1
   4:   aload_1
   5:   invokeinterface #36,  1; //InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
   10:  astore_3
   11:  goto    28
   14:  aload_3
   15:  invokeinterface #42,  1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
   20:  astore_2
   21:  getstatic   #48; //Field java/lang/System.out:Ljava/io/PrintStream;
   24:  aload_2
   25:  invokevirtual   #54; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   28:  aload_3
   29:  invokeinterface #60,  1; //InterfaceMethod java/util/Iterator.hasNext:()Z
   34:  ifne    14
   37:  return

Danke alle für die Antworten!

Update 2 : Ich habe verleiten mit Eclipse-IDE, die verwendet seine eigene Compiler so tatsächlich der Bytecode oben ist es das man die Eclipse-Compiler . Schauen Sie hier , wie kompilieren manuell Code mit Eclipse. Abschließend erzeugen Eclipse-Compiler unterschiedlichen Byte-Code aus den Sun-Compiler in einigen Fällen, unabhängig von der Plattform, die hier beschriebenen Fall einer zu sein.

War es hilfreich?

Lösung

Should nicht, dass Code immer ein ClassCastException werfen? Es tut mir die Sun Java 6-Compiler und Laufzeit (unter Linux) verwendet wird. Sie Casting Integers als Strings. Der Iterator erstellt wird eine Iterator<String> sein, aber dann versucht es das erste Element zuzugreifen, das ein Integer ist, und so ist es nicht.

Dies wird klarer, wenn Sie Ihre Array ändern wie folgt:

return Arrays.asList("one", 2, 3);

Nun ist die Schleife funktioniert tatsächlich für das erste Element, weil das erste Element ein String ist und wir sehen den Ausgang; dann die Iterator<String> auf dem zweiten fehlschlägt, weil es nicht eine Zeichenfolge ist.

Ihr Code funktioniert, wenn Sie nur eine generische List anstelle eines spezifischen verwenden:

List list = getObjects();
for (Object o : list) {
    System.out.println(o);
}

... oder natürlich, wenn Sie List<Integer> verwenden, da der Inhalt Integers. Was Sie tun, jetzt löst eine Compiler-Warnung - Note: Generics.java uses unchecked or unsafe operations. -. Und das aus gutem Grund

Diese Änderung auch funktioniert:

for (Object o : (List)list)

... vermutlich, weil zu diesem Zeitpunkt Sie es zu tun mit einem Iterator, kein Iterator<String>.

bozho hat gesagt, er diesen Fehler nicht auf Windows XP nicht sehen (nicht erwähnt, welche Compiler und Laufzeit, aber ich vermute, Sun), und Sie sagen, Sie sehen es nicht (oder nicht zuverlässig), so klar ist, dass eine Umsetzung Empfindlichkeit hier, aber das Endergebnis ist: Do not List<String> zu interact mit einem List von Integers verwenden. : -)

Hier ist die Datei, die ich bin Kompilieren:

import java.util.Arrays;
import java.util.List;

public class Generics {

    static List getObjects() {
        return Arrays.asList("one", 2, 3);
    }

    public static void main(String[] args) {
        List<String> list = getObjects();
        for (Object o : list) { // ClassCastException?
            System.out.println(o);
        }
    }
}

Hier ist die Zusammenstellung:

tjc@forge:~/temp$ javac Generics.java 
Note: Generics.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

Hier ist der Lauf:

tjc@forge:~/temp$ java Generics 
one
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at Generics.main(Generics.java:12)

Zeile 12 ist die for Aussage. Beachten Sie, dass es das erste Element hat Ausgang, weil ich, dass auf eine String geändert. Es hat die andere nicht ausgegeben. (Und bevor ich diese Änderung vorgenommen hat, es scheiterte sofort.)

Hier ist der Compiler verwende ich:

tjc@forge:~/temp$ which javac
/usr/bin/javac
tjc@forge:~/temp$ ll /usr/bin/javac
lrwxrwxrwx 1 root root 23 2010-09-30 16:37 /usr/bin/javac -> /etc/alternatives/javac*
tjc@forge:~/temp$ ll /etc/alternatives/javac
lrwxrwxrwx 1 root root 33 2010-09-30 16:37 /etc/alternatives/javac -> /usr/lib/jvm/java-6-sun/bin/javac*

Hier ist die Demontage, die die checkcast zeigt:

tjc@forge:~/temp$ javap -c Generics
Compiled from "Generics.java"
public class Generics extends java.lang.Object{
public Generics();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

static java.util.List getObjects();
  Code:
   0:   iconst_3
   1:   anewarray   #2; //class java/io/Serializable
   4:   dup
   5:   iconst_0
   6:   ldc #3; //String one
   8:   aastore
   9:   dup
   10:  iconst_1
   11:  iconst_2
   12:  invokestatic    #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   15:  aastore
   16:  dup
   17:  iconst_2
   18:  iconst_3
   19:  invokestatic    #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   22:  aastore
   23:  invokestatic    #5; //Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
   26:  areturn

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #6; //Method getObjects:()Ljava/util/List;
   3:   astore_1
   4:   aload_1
   5:   invokeinterface #7,  1; //InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
   10:  astore_2
   11:  aload_2
   12:  invokeinterface #8,  1; //InterfaceMethod java/util/Iterator.hasNext:()Z
   17:  ifeq    40
   20:  aload_2
   21:  invokeinterface #9,  1; //InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
   26:  checkcast   #10; //class java/lang/String
   29:  astore_3
   30:  getstatic   #11; //Field java/lang/System.out:Ljava/io/PrintStream;
   33:  aload_3
   34:  invokevirtual   #12; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   37:  goto    11
   40:  return

}

Auch hier, obwohl, hat unter dem Strich sein: Verwenden Sie keine List<String> zu interact mit einem List verwenden, die Dinge enthält, die nicht Strings sind. : -)

Andere Tipps

Ich kann es auch nicht reproduzieren, aber ich folgende Fehler erkennen, die behoben werden müssen:

  • make getObjects() Rückkehr List<Integer>, anstatt eine rohe Art
  • Sie nicht erwarten List<String>, sondern eine List<Integer> statt
  • Wenn Iterieren, Schleife for (Integer o : list)

Das Problem ist die Methode static List getObjects() { gibt einen allgemeinen (nicht parametrisierte) List. Und Sie weisen es List<String>. Diese Linie sollte eine Compiler-Warnung geben, und das soll ein Problem gemeldet hat.

Dieser Teil:

List<String> list = getObjects();
for (Object o : list) { // ClassCastException?
    System.out.println(o);
}

Wird vereinfacht werden

List<String> list = getObjects();
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    Object o = iterator.next();
    System.out.println(o);
}

Aber die Umsetzung des Iterator wird gegossen versuchen, wenn sie von der next() in einem Iterator der String Methode den Inhalt send.

Aus diesem Grund haben Sie einen CCE.

Lösungen:

Entweder überall Verwendung Generika oder benutzt sie nicht, aber es ist wirklich wichtig consistant zu sein. Wenn Sie eine List<Integer> oder ein List<? super Integer> zurückgekehrt war würden Sie dieses Problem bei der Kompilierung gesehen haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top