Shouldn't that code always throw a ClassCastException
? It does for me using the Sun Java 6 compiler and runtime (on Linux). You're casting Integer
s as String
s. The iterator created will be an Iterator<String>
, but then it tries to access the first element, which is an Integer
, and so it fails.
This gets clearer if you change your array like so:
return Arrays.asList("one", 2, 3);
Now the loop actually works for the first element, because the first element is a String
and we see the output; then the Iterator<String>
fails on the second one, because it isn't a string.
Your code works if you just use a generic List
instead of a specific one:
List list = getObjects();
for (Object o : list) {
System.out.println(o);
}
...or, of course, if you use List<Integer>
, since the contents are Integer
s. What you're doing now triggers a compiler warning — Note: Generics.java uses unchecked or unsafe operations.
— and for good reason.
This modification also works:
for (Object o : (List)list)
...presumably because at that point you're dealing with an Iterator
, not an Iterator<String>
.
bozho has said he doesn't see this error on Windows XP (didn't mention which compiler and runtime, but I'm guessing Sun's), and you say you're not seeing it (or not reliably), so clearly there's some implementation sensitivity here, but the bottom line is: Don't use List<String>
to interact with a List
of Integer
s. :-)
Here's the file I'm compiling:
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);
}
}
}
Here's the compilation:
tjc@forge:~/temp$ javac Generics.java
Note: Generics.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Here's the run:
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)
Line 12 is the for
statement. Note that it did output the first element, because I changed that to a String
. It didn't output the others. (And before I made that change, it failed immediately.)
Here's the compiler I'm using:
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*
Here's the disassembly, which shows the checkcast
:
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
}
Again, though, the bottom line has to be: Don't use a List<String>
to interact with a List
that contains things that aren't String
s. :-)
java.lang.ClassCastException: XXXX cannot be cast to YYYY
. (2) The line number sometimes off by a few lines, so look a few lines above and below the reported line for possible sources of the exception. – Metaplasiacheckcast
being in some compiled versions (mine, Tim's when he used 1.6.0_21) and not others (bozho's, yours)... – Marengo