Java generics Strange behavior

Ilya Gazman

In Java Integer extends Number

Then next code is compiling:

List<Number> list1 = null;
List<? super Integer> list2 = null;
list2 = list1;

While this code is not compiling:

List<? super Number> list1 = null;
List<? extends Integer> list2= null;
list1 = list2;

The question is why?

Rohit Jain

Let's see what would go wrong if it would have compiled:

// Suppose list1, and list2 are initialized like this
List<? super Number> list1 = new ArrayList<Object>();  // valid assignment
List<? extends Integer> list2 = new ArrayList<Integer>();  // valid

// had this been valid, list1 and list2 both point to ArrayList<Integer>
list1 = list2;   

// This is fine, as list1 declared type is `List<? super Number>`
list1.add(new Float(2.4f));

// The below code will compile fine, as list2.get(0) type is Integer.
// But it would throw ClassCastException at runtime.
Integer in = list2.get(0);  

So, to avoid it runtime, compiler gives you a compile time error.

For the first case however, you have somehow reversed the assignment, so the comparison between the 2 codes doesn't make sense. Change the first code to:

List<Number> list1 = null;
List<? super Integer> list2 = null;
list1 = list2;  

and it will fail too.

Also, reversing the assignment in the 2nd code would also make the code fail to compile.

Some explanation:

What you must remember is, a super class reference can point to a subclass object, but not the reverse. If all the lists that can be capture-converted from list1 are also capture convertible from the declared type of list2, then the assignment list2 = list1 would be valid, else it would fail to compile.

For the first code:

  • List<? super Integer> can be capture converted to the following lists:
    • List<Integer>
    • List<Number>
    • List<Object>
    • List<Serializable>

Since List<Number> is there in the list, so assignment list2 = list1 is valid, as list1 can only point to a List<Number>. But, the reverse assignment list1 = list2 is not valid, as List<Integer> is not a subtype of List<Number>.

Similarly, for the 2nd code:

  • List<? super Number> can be capture-converted to:

    • List<Object>
    • List<Serializable>
    • List<Number>
  • List<? extends Integer> can be capture-converted to:

    • List<Integer>

Since List<Integer> is not capture-convertible from List<? super Number>, so list1 = list2 is invalid.

Also, since List<Object> and all other lists are not capture-convertible from List<? extends Integer>, so list2 = list1 is also invalid.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related