Reputation: 1783
How would you describe – in plain english – the difference between the contents of these lists?
I'm looking for a simple comparison that can be used as a reference.
/* 1 */ List< List< Dog>>
/* 2 */ List< List<? extends Dog>>
/* 3 */ List<? extends List< Dog>>
/* 4 */ List<? extends List<? extends Dog>>
The generic declarations with super
are similar. So what about these:
/* 5 */ List<? super List<? extends Dog>>
/* 6 */ List<? extends List<? super Dog>>
Upvotes: 2
Views: 137
Reputation: 11877
List
whose elements are lists of dogsList
whose elements are lists of a type that extends Dog
List
whose elements are a single subtype of a list of dogsList
whose elements are a single subtype of a (list of a type that extends Dog
)List
whose elements are a single supertype of a (list of a type that extends Dog
)List
whose elements are a single subtype of a (list of a type that super Dog
)Where "subtype", "supertype", "super", and "extends" are the "generic" versions (i.e. also includes the bounding type)
Examples with Number
and subtypes, because why not. Replace Dog
with Number
.
List<List<Number>>
might look like a 2D array of Number
elements. Pretty simple.
List<List<? extends Number>>
might look like a 2D array, where each row is a different subtype of number. For example, the first row might be a List<Integer>
, the second row might be a List<Double>
, etc.
List<? extends List<Number>>
might be a List<ArrayList<Number>>
, List<List<Number>>
, List<LinkedList<Number>>
, etc. The Number
has to stay, because generics are invariant, but you can have List
or any of its subtypes as the "overall" type of the elements. You can only pick one of List
or its subtypes though, and the one you pick you have to stay with.
List<? extends List<? extends Number>>
is similar to List<? extends List<Number>>
, except now you can pick Number
or any of its subclasses as the elements of the "overall" 2D array. So you can have List<List<Integer>>
, List<ArrayList<Integer>>
, List<LinkedList<Double>>
, etc. As before, you can only pick one of List
's subtypes and one of Number
's subtypes.
List<? super List<? extends Number>>
appears to be equivalent to List<List<? extends Number>>
, List<Collection<? extends Number>>
, etc. but not List<List<Number>>
or anything concrete where a subtype of Number
is used. I think this is because List<Number>
isn't considered a supertype of List<? extends Number>
, which I suppose makes sense due to generics being invariant. List<Object>
as well as raw types (List<List>
, List<Collection>
, etc.) also works. List<Number>
or List<Object>
(and apparently List<Serializable>
) as the inner list.As @MadProgrammer said, due to PECS (Producer-Extends-Consumer-Super), any time you have a ? extends
for your generic type you won't be able to update the list, only retrieve items from it. So no add()
-ing and no set()
-ing.
Upvotes: 7
Reputation: 31300
Replace each "<" by "of".
Whenever there is a "? extends X", insert "or one of its subclasses" after X.
Upvotes: 1
Reputation: 10604
The first one is concrete: it's a List
of List
s of Dog
, and nothing else.
The second one is abstract on the innermost declaration: it's a List
of List
s of some class that inherits from Dog
-- say Poodle
. It might be a List<ArrayList<Poodle>>
.
The third one is abstract on the inner list declaration: its a List
of some sort of container that inherits from List
-- maybe ArrayList
-- of Dog
. Then you might have List<ArrayList<Dog>>
.
The fourth one is abstract on both: its a List
of some kind of container derived from List
, filled with some animal that inherits from Dog
-- maybe List<ArrayList<Poodle>>
.
Upvotes: 1