When I try to compile the following code:
LinkedList<List<? extends Number>> numList = new LinkedList<List<Integer>>();
I get an incompatible type error:
Required: LinkedList <java.util.list<? extends java.lang.Number>>
Found: LinkedList <java.util.list<Integer>>
How can I achieve having a LinkedList
which contains elements that are List
s with elements that extend Number
?
To be clear, I'm looking to add lists to numList
in the following fashion:
numList.add(new LinkedList<Integer>());
Wildcard capture does not go more than one generic level deep. So while this works:
This does not:
The most reasonable explanation I can think of is to think of generics as invariant at the outermost level. A
LinkedList<List<Integer>>
is not aLinkedList<List<? extends Number>>
, even though aList<Integer>
is aList<? extends Number>
, for the same reason that aList<Dog>
is not aList<Animal>
even though aDog
is anAnimal
. Here,Dog
is toAnimal
asList<Integer>
is toList<? extends Number>
.Well, the Dog/Animal solution is
? extends
:Applying the same reasoning, the workaround is another
? extends
:However, you won't be able to add anything to this list because of the first
? extends
. The reference type variablenumList
doesn't know which subtype ofList<? extends Number>
it really is; it could beArrayList<Integer>
, so Java cannot provide the type safety that such a thing can be added to such aLinkedList
. To maintain type safety, the compiler will only allow addingnull
. You'll have to match the generic type parameters exactly, with no wildcards:LinkedList<List<Integer>> numList = new LinkedList<List<Integer>>();
. You can add aList<Integer>
to such aLinkedList
.