Generics - are shuffle types allowed?

I used to run some tests and could not find an explanation why this code does what it does:

public class Test { public static void main(String[] args) { List<Integer> list = new ArrayList(Arrays.asList(Double.valueOf(0.1234))); System.out.println(list.get(0)); //prints 0.1234 Object d = list.get(0); System.out.println(d.getClass()); // prints class java.lang.Double System.out.println(list.get(0).getClass()); // ClassCastException } } 

This raises several questions:

  • Why does List <Integer> accept double first (should it even compile)?
  • why is the second printed work, not the third, although it looks like they are doing the same?

EDIT
I understand the following 2 statements:

 List aList = new ArrayList(); //I can add any objects in there List<Integer> aList = new ArrayList<Integer>(); //I can only add something that extends Integer in there 

But I don’t understand why this is allowed and why it works to some extent at runtime, although some operations throw a ClassCastException - I would expect a ClassCastException in the first line of code published above:

 List<Integer> aList = new ArrayList(); //I can any objects in there 
+3
java generics
source share
3 answers

If you write

 ... new ArrayList<Integer>(... 

instead, it will throw a compiler exception.

Why does it work:

 System.out.println(list.get(0)); //prints 0.1234 

The Object.toString() method is the same as in Double and Integer (And since System.out.println() expects the object to not be passed to Integer (the compiler optimized the drop))

 Object d = list.get(0); System.out.println(d.getClass()); // prints class java.lang.Double 

The same goes for .getClass() . Here, the optimizer dropped the throw again.

 System.out.println(list.get(0).getClass()); // ClassCastException 

This actually creates an Integer from the list, and it fails. He throws because the optimizer decided that he needs to do this, because it is not obvious that he does not need it.

If you change this last line to:

  System.out.println(((Object)list.get(0)).getClass()); 

it works:)

+5
source share

It:

 new ArrayList(Arrays.asList(Double.valueOf(0.1234))) 

creates a raw (untyped) ArrayList into which you can put anything. This is the right way to do this:

 new ArrayList<Integer>(Arrays.asList(Double.valueOf(0.1234))) 

which should not compile now.

+6
source share

The second does not work, because when you use generics, the compiler inserts casts for you (you do not have to). The compiler is trying to pass an element to Integer because it is a generic list type.

Since you added to the list via unchecked add, something is now in the list that was not checked at its entry, so it fails at the exit.

0
source share

All Articles