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:
LinkedList<? extends Number> test = new LinkedList<Integer>();
This does not:
LinkedList<List<? extends Number>> numList = new LinkedList<List<Integer>>();
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 a LinkedList<List<? extends Number>>
, even though a List<Integer>
is a List<? extends Number>
, for the same reason that a List<Dog>
is not a List<Animal>
even though a Dog
is an Animal
. Here, Dog
is to Animal
as List<Integer>
is to List<? extends Number>
.
Well, the Dog/Animal solution is ? extends
:
List<? extends Animal> animals = new List<Dog>();
Applying the same reasoning, the workaround is another ? extends
:
LinkedList<? extends List<? extends Number>> numList = new LinkedList<List<Integer>>();
However, you won't be able to add anything to this list because of the first ? extends
. The reference type variable numList
doesn't know which subtype of List<? extends Number>
it really is; it could be ArrayList<Integer>
, so Java cannot provide the type safety that such a thing can be added to such a LinkedList
. To maintain type safety, the compiler will only allow adding null
. You'll have to match the generic type parameters exactly, with no wildcards: LinkedList<List<Integer>> numList = new LinkedList<List<Integer>>();
. You can add a List<Integer>
to such a LinkedList
.