Reputation: 32221
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?
Upvotes: 0
Views: 306
Reputation: 213223
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.
Upvotes: 5
Reputation: 83235
(1) In the first example, List<Number>
is "captured" by of List<? super Integer>
. A List<Number>
is a List<? super Integer>
.
(2) But in the second example, List<? extends Integer>
is not captured by List<? super Number>
.
For example, you can add Number
s to List<? super Number>
, but you cannot add non-Integer
Number
s to List<? extends Integer>
.
List<? super Number> list1 = new ArrayList<Number>();
list1.add(0.5); //okay
List<? extends Integer> list2 = new ArrayList<Integer>();
list2.add(0.5); //not okay
Therefore, you cannot assign list1
to be list2
, since list2
does not support everything that the type of list1
should.
Upvotes: 0