generics - ClassCastException in Java foreach loop -
in circumstances can classcastexception occur in code below:
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(); (object o : list) { // classcastexception? system.out.println(o); } } }
we had similar case in production environment (bad practice, know) , customer provided log classcastexception @ line comment can't seem reproduce it. thoughts?
i know jvm creates iterator in background when using foreach, can create raw iterator in cases , parametrized 1 in other cases?
update:i had @ bytecode generated , on windows, using jdk 1.6.0_21-b07 no checkcast made. interesting :)
here main method:
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
thanks answers!
update 2: got mislead eclipse ide uses own compiler bytecode above it's 1 generated using eclipse compiler. here how manually compile code eclipse. in conclusion eclipse compiler generates different byte-code sun compiler in cases, regardless of platform, case described here being one.
shouldn't code always throw classcastexception
? me using sun java 6 compiler , runtime (on linux). you're casting integer
s string
s. iterator created iterator<string>
, tries access first element, integer
, , fails.
this gets clearer if change array so:
return arrays.aslist("one", 2, 3);
now loop works first element, because first element string
, see output; iterator<string>
fails on second one, because isn't string.
your code works if use generic list
instead of specific one:
list list = getobjects(); (object o : list) { system.out.println(o); }
...or, of course, if use list<integer>
, since contents integer
s. you're doing triggers compiler warning — note: generics.java uses unchecked or unsafe operations.
— , reason.
this modification works:
for (object o : (list)list)
...presumably because @ point you're dealing iterator
, not iterator<string>
.
bozho has said doesn't see error on windows xp (didn't mention compiler , runtime, i'm guessing sun's), , you're not seeing (or not reliably), there's implementation sensitivity here, bottom line is: don't use list<string>
interact list
of integer
s. :-)
here's 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(); (object o : list) { // classcastexception? system.out.println(o); } } }
here's compilation:
tjc@forge:~/temp$ javac generics.java note: generics.java uses unchecked or unsafe operations. note: recompile -xlint:unchecked details.
here's run:
tjc@forge:~/temp$ java generics 1 exception in thread "main" java.lang.classcastexception: java.lang.integer cannot cast java.lang.string @ generics.main(generics.java:12)
line 12 for
statement. note did output first element, because changed string
. didn't output others. (and before made change, failed immediately.)
here's compiler i'm using:
tjc@forge:~/temp$ 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 disassembly, shows checkcast
:
tjc@forge:~/temp$ javap -c generics compiled "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 1 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, bottom line has be: don't use list<string>
interact list
contains things aren't string
s. :-)
Comments
Post a Comment