Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics - mixing types allowed?

Tags:

java

generics

I was running some tests earlier and could not find an explanation as to 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
    }
}

That raises a few questions:

  • why does the List<Integer> accept a Double in the first place (should it compile at all)?
  • why does the second print work and not the third, although it looks like they are doing the same thing?

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 one is authorised and why it actually works to some extent at runtime although some operations produce a ClassCastException - I would have expected a ClassCastException at the first line of the code posted above:

List<Integer> aList = new ArrayList(); //I can any objects in there
like image 522
assylias Avatar asked Aug 28 '26 18:08

assylias


2 Answers

This:

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

creates a raw (untyped) ArrayList, in to which you can place anything. This is the correct way to do it:

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

which should now not compile.

like image 167
Oliver Charlesworth Avatar answered Aug 31 '26 08:08

Oliver Charlesworth


If you write

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

instead it will cause a compiler exception.

On why it works:

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

The method Object.toString() is the same in Double and Integer (And because System.out.println() expects an Object this is not cast into an Integer (the compiler optimized the cast away))

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

Same goes for .getClass(). Here the optimizer again dropped the cast.

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

This actually creates an Integer from the list and that fails. It does the cast because the optimizer thought it need to do it, because its not obvious that it doesn't need to.

If you would change that last line to:

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

it works :)

like image 24
Angelo Fuchs Avatar answered Aug 31 '26 08:08

Angelo Fuchs