What is the difference between List<? super T>
and List<? extends T>
?
I used to use List<? extends T>
, but it does not allow me to add elements to it list.add(e)
, whereas the List<? super T>
does.
extends
The wildcard declaration of List<? extends Number> foo3
means that any of these are legal assignments:
List<? extends Number> foo3 = new ArrayList<Number>(); // Number "extends" Number (in this context)
List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>(); // Double extends Number
Reading - Given the above possible assignments, what type of object are you guaranteed to read from List foo3
:
Number
because any of the lists that could be assigned to foo3
contain a Number
or a subclass of Number
.Integer
because foo3
could be pointing at a List<Double>
.Double
because foo3
could be pointing at a List<Integer>
.Writing - Given the above possible assignments, what type of object could you add to List foo3
that would be legal for all the above possible ArrayList
assignments:
Integer
because foo3
could be pointing at a List<Double>
.Double
because foo3
could be pointing at a List<Integer>
.Number
because foo3
could be pointing at a List<Integer>
.You can't add any object to List<? extends T>
because you can't guarantee what kind of List
it is really pointing to, so you can't guarantee that the object is allowed in that List
. The only "guarantee" is that you can only read from it and you'll get a T
or subclass of T
.
super
Now consider List <? super T>
.
The wildcard declaration of List<? super Integer> foo3
means that any of these are legal assignments:
List<? super Integer> foo3 = new ArrayList<Integer>(); // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>(); // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>(); // Object is a superclass of Integer
Reading - Given the above possible assignments, what type of object are you guaranteed to receive when you read from List foo3
:
Integer
because foo3
could be pointing at a List<Number>
or List<Object>
.Number
because foo3
could be pointing at a List<Object>
.Object
or subclass of Object
(but you don't know what subclass).Writing - Given the above possible assignments, what type of object could you add to List foo3
that would be legal for all the above possible ArrayList
assignments:
Integer
because an Integer
is allowed in any of above lists.Integer
because an instance of a subclass of Integer
is allowed in any of the above lists.Double
because foo3
could be pointing at an ArrayList<Integer>
.Number
because foo3
could be pointing at an ArrayList<Integer>
.Object
because foo3
could be pointing at an ArrayList<Integer>
.Remember PECS: "Producer Extends, Consumer Super".
"Producer Extends" - If you need a List
to produce T
values (you want to read T
s from the list), you need to declare it with ? extends T
, e.g. List<? extends Integer>
. But you cannot add to this list.
"Consumer Super" - If you need a List
to consume T
values (you want to write T
s into the list), you need to declare it with ? super T
, e.g. List<? super Integer>
. But there are no guarantees what type of object you may read from this list.
If you need to both read from and write to a list, you need to declare it exactly with no wildcards, e.g. List<Integer>
.
Note this example from the Java Generics FAQ. Note how the source list src
(the producing list) uses extends
, and the destination list dest
(the consuming list) uses super
:
public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i = 0; i < src.size(); i++)
dest.set(i, src.get(i));
}
}
Also see How can I add to List<? extends Number> data structures?