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 guarenteed to read from List foo3
:
- You can read a
Number
because any of the lists that could be assigned tofoo3
contain aNumber
or a subclass ofNumber
. - You can't read an
Integer
becausefoo3
could be pointing at aList<Double>
. - You can't read a
Double
becausefoo3
could be pointing at aList<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:
- You can't add an
Integer
becausefoo3
could be pointing at aList<Double>
. - You can't add a
Double
becausefoo3
could be pointing at aList<Integer>
. - You can't add a
Number
becausefoo3
could be pointing at aList<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
:
- You aren't guaranteed an
Integer
becausefoo3
could be pointing at aList<Number>
orList<Object>
. - You aren't guaranteed an
Number
becausefoo3
could be pointing at aList<Object>
. - The only guarantee is that you will get an instance of an
Object
or subclass ofObject
(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:
- You can add an
Integer
because anInteger
is allowed in any of above lists. - You can add an instance of a subclass of
Integer
because an instance of a subclass ofInteger
is allowed in any of the above lists. - You can't add a
Double
becausefoo3
could be pointing at aArrayList<Integer>
. - You can't add a
Number
becausefoo3
could be pointing at aArrayList<Integer>
. - You can't add a
Object
becausefoo3
could be pointing at aArrayList<Integer>
.
PECS
Remember PECS: "Producer Extends, Consumer Super".
-
"Producer Extends" - If you need a
List
to produceT
values (you want to readT
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 consumeT
values (you want to writeT
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>
.
Example
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));
}
}