Java foreach循环中的ClassCastException

Java foreach循环中的ClassCastException,java,generics,iterator,foreach,classcastexception,Java,Generics,Iterator,Foreach,Classcastexception,在什么情况下,ClassCastException会出现在下面的代码中: 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<S

在什么情况下,ClassCastException会出现在下面的代码中:

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);
        }
    }
}
导入java.util.array;
导入java.util.List;
公共类泛型{
静态列表getObjects(){
返回数组.asList(1,2,3);
}
公共静态void main(字符串[]args){
List=getObjects();
对于(对象o:list){//ClassCastException?
系统输出打印ln(o);
}
}
}
我们在一个生产环境中遇到了类似的情况(我知道,这是一个糟糕的做法),客户提供了一个带有ClassCastException的日志,其中有注释,但我似乎无法复制它。有什么想法吗

我知道当使用foreach时,JVM会在后台创建一个迭代器,但在某些情况下它能创建一个原始迭代器,在其他情况下它能创建一个参数化迭代器吗

更新:我还查看了生成的字节码,并在Windows上使用JDK 1.6.0_21-b07进行了检查。有趣:)

以下是主要方法:

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 公共静态void main(java.lang.String[]); 代码: 0:invokestatic#34//方法getObjects:()Ljava/util/List; 3:astore_1 4:aload_1 5:调用接口#36,1//interface方法java/util/List.iterator:()Ljava/util/iterator; 10:astore_3 11:goto 28 14:aload_3 15:调用接口#42,1//接口方法java/util/Iterator.next:()Ljava/lang/Object; 20:astore_2 21:getstatic#48//字段java/lang/System.out:Ljava/io/PrintStream; 24:aload_2 25:invokevirtual#54//方法java/io/PrintStream.println:(Ljava/lang/Object;)V 28:aload_3 29:调用接口#60,1//InterfaceMethod java/util/Iterator.hasNext:()Z 34:ifne 14 37:返回 谢谢大家的回答

更新2:我被Eclipse IDE误导,该IDE使用了它的字节码,因此实际上上面的字节码是使用Eclipse编译器生成的。了解如何使用Eclipse手动编译代码。 总之,Eclipse编译器在某些情况下会从Sun编译器生成不同的字节码,而不管平台是什么,这里描述的情况就是这样一种情况。

该代码不应该总是抛出
ClassCastException
?它为我使用Sun Java 6编译器和运行时(在Linux上)提供了支持。您正在将
Integer
s转换为
String
s。创建的迭代器将是一个
迭代器
,但随后它尝试访问第一个元素,即
整数
,因此失败

如果您这样更改阵列,这一点会更清楚:

return Arrays.asList("one", 2, 3);
现在循环实际上对第一个元素起作用,因为第一个元素是一个
字符串
,我们可以看到输出;然后,
迭代器在第二个迭代器上失败,因为它不是字符串

如果您只使用一个通用的
列表而不是一个特定的列表,那么您的代码是有效的:

List list = getObjects();
for (Object o : list) {
    System.out.println(o);
}
…或者,当然,如果您使用
列表
,因为内容是
整数
s。您现在所做的操作会触发编译器警告-
注意:Generics.java使用未经检查或不安全的操作。
-这是有充分理由的

这种修改也适用于:

for (Object o : (List)list)
…大概是因为此时您处理的是
迭代器
,而不是
迭代器

bozho说他在WindowsXP上没有看到这个错误(没有提到哪个编译器和运行时,但我猜是Sun的),你说你没有看到它(或者不可靠),所以很明显这里有一些实现敏感性,但底线是:不要使用
List
整数的
列表进行交互

以下是我正在编译的文件:

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);
        }
    }
}
下面是反汇编,它显示了
复选框

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 } tjc@forge:~/temp$javap-c泛型 从“Generics.java”编译而来 公共类泛型扩展了java.lang.Object{ 公共仿制药(); 代码: 0:aload_0 1:invokespecial#1;//方法java/lang/Object。“:()V 4:返回 静态java.util.List getObjects(); 代码: 0:iconst_3 1:anewarray#2;//类java/io/Serializable 4:dup 5:iconst_0 6:ldc#3;//字符串一 8:aastore 9:dup 10:iconst_1 11:iconst_2 12:invokestatic#4;//方法java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 15:aastore 16:dup 17:iconst_2 18:iconst_3 19:invokestatic#4;//方法java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 22:aastore 23:invokestatic#5;//方法java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List; 26:轮到你了 公共静态void main(java.lang.String[]); 代码: 0:invokestatic#6;//方法getObjects:()Ljava/util/List; 3:astore_1 4:aload_1 5:invokeinterface#7,1;//接口方法java/util/List.iterator:()Ljava/util/iterator; 10:astore_2 11:aload_2 12:invokeinterface#8,1;//接口方法java/util/Iterator.hasNext:()Z 17:ifeq 40 20:aload_2 21:invokeinterface#9,1;//接口方法java/util/Iterator.next:()Ljava/lang/Object; 26:checkcast#10;//类java/lang/String 29:astore_3 30:getstatic#11;//字段java/lang/System.out:Ljava/io/PrintStream; 33:aload_3 34:invokevirtual#12;//方法java/io/PrintStream.println:(Ljava/lang/Object;)V 37:goto 11 40:返回 }
同样,底线必须是:不要使用
列表
与包含非
字符串的内容的
列表
交互。:-)

我也无法重现,但我发现以下错误必须纠正:

  • 使
    getObjects()
    返回
    List
    ,而不是原始类型
  • 不要期望
    列表
    ,而是一个
    列表
  • 迭代时,循环(整数o:list)

    问题在于方法
    static List getObjects(){
    返回泛型(非参数 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) 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* 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 }
    List<String> list = getObjects();
    for (Object o : list) { // ClassCastException?
        System.out.println(o);
    }
    
    List<String> list = getObjects();
    for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
        Object o = iterator.next();
        System.out.println(o);
    }