Community
Participate
Working Groups
Consider the followoing example: ---- import java.util.ArrayList; import java.util.List; public class ForEachTest { public static void main(String[] args) { final List<String> stringList = new ArrayList<String>(); stringList.add("test1"); stringList.add("test2"); ((List) stringList).add(new Integer(1000)); for (Object obj : stringList) { // line 11 System.out.println(obj); } } } ---------- The latest Eclipse 3.3.1.1 compiler compiles it and the program runs fine with output: test1 test2 1000 With javac (for example version 1.6.0_01-b06 under Windows) the program compiles but the program fails with output: test1 test2 Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at ForEachTest.main(ForEachTest.java:11) The javac makes a cast on the next iterator in the bytecode whereas the eclipse compiler ommits the cast. The Java language spec doesn't say anything about it, but it's irritating.
Feels like we are doing the right thing. We would issue the ClassCastException if code was performing: for (String str : stringList) { // line 11 System.out.println(str); } But since the code is manipulating the list as objects, we do not insert cast to String checks. Interestingly, if you write instead: import java.util.ArrayList; import java.util.List; public class X { public static void main(String[] args) { final List<String> stringList = new ArrayList<String>(); stringList.add("test1"); stringList.add("test2"); ((List) stringList).add(new Integer(1000)); Object o = stringList.get(2); } } No ClassCastException is generated any longer, from javac output. Strictly speaking, I don't see why any would be different from the other. By using an Object variable in the foreach loop, the #println(Object) is selected, and thus no String cast should be required.
You're right there should be no difference between both codes since the return type of both the next iterator and the get method is String in our example. But by decompiling the output of the javac one sees the cast: for(Iterator iterator = arraylist.iterator(); iterator.hasNext(); System.out.println(s)) s = (String)iterator.next(); -- Object obj = arraylist.get(2); ------------- That's not very consistant from the javac. I don't know if it's y bug from Eclipse compiler or from the java compiler but I wanted to report the mismatch between both.
Yes, the inserted cast is visible in bytecode. Knowing the mismatch is good, I am investigating whether there would be a secret entry in the spec which would explain the difference. So far, I am leaning towards a javac bug... but this is still premature.
Added GenericTypeTest#test1219
Got confirmation from spec master that our behavior is the proper one. This is a javac bug which you should report to them. Closing as INVALID since our behavior is valid.
In his Post on dev.java.net (http://forums.java.net/jive/thread.jspa?messageID=246154#246154) Nishanth Sastry tells us that the behavior of the javac is correct and eclipse should throw an Exception. We will look at it and maybe write another comment here.
Verified for 3.4M4 using build I20071210-1800.
As reported in bug 232487, javac bug has been identified since as http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6500701.