Java foreach循环中的ClassCastException
在什么情况下,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
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);
}