What change of JLS 6/7 causes the following unchecked code with collections and generics to work in Java 7?

StackOverflow https://stackoverflow.com/questions/18486018

  •  26-06-2022
  •  | 
  •  

Question

The following code

import java.util.*;
import java.io.*;

@SuppressWarnings("unchecked")
List<Serializable> list = (List<Serializable>) (List<?>)
  Collections.singletonList(new Object());

for (Object el : list) { // -> ClassCastException
  System.out.println(el);
}

is correct Java (even though the code is suspicious). Using javac and java 6 it throws

Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.io.Serializable

while it runs without error when using javac and java 7.

Is it a language change, fixed bug or a hidden feature?

(Note: Code compiled with Eclipse runs without error on all Eclipse versions checked - Helios to Kepler.)

Was it helpful?

Solution

You're polluting the heap by adding your raw Object to the collection (which you're having to do the cast dance to make happen). It's not technically illegal, but it is a bug.

When you are pulling the value out of your implicit iterator, the Java 6 compiler appears to be casting immediately, while the Java 7 compiler isn't. It's more efficient not to cast to Serializable if it doesn't need to (since the holding variable is just Object), but this behavior is undefined as far as I understand from the JLS. Try running javap on your two .class files and looking at the code right around that for loop (probably right after an invokeinterface call to Iterator.next()).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top