Difference between <? super T> and <? extends T> in Java
What is the difference between List<? super T> List<? super T> and List<? extends T> List<? extends T> ?
I used to use List<? extends T> List<? extends T> , but it does not allow me to add elements to it list.add(e) , whereas the List<? super T> List<? super T> does.
extends
The wildcard declaration of List<? extends Number> foo3 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> 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> List <? super T> .
The wildcard declaration of List<? super Integer> foo3 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> . PECS
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 ? extends T , eg List<? extends Integer> 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 ? super T , eg List<? super Integer> 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, eg 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));
}
}
Also see How can I add to List<? extends Number> data structures?
Imagine having this hierarchy

1. Extends
By writing
List<? extends C2> list;
you are saying that list will be able to reference an object of type (for example) ArrayList whose generic type is one of the 7 subtypes of C2 ( C2 included):
new ArrayList<C2>(); , (an object that can store C2 or subtypes) or new ArrayList<D1>(); , (an object that can store D1 or subtypes) or new ArrayList<D2>(); , (an object that can store D2 or subtypes) or... and so on. Seven different cases:
1) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4
2) new ArrayList<D1>(): can store D1 E1 E2
3) new ArrayList<D2>(): can store D2 E3 E4
4) new ArrayList<E1>(): can store E1
5) new ArrayList<E2>(): can store E2
6) new ArrayList<E3>(): can store E3
7) new ArrayList<E4>(): can store E4
We have a set of "storable" types for each possible case: 7 (red) sets here graphically represented

As you can see, there is not a safe type that is common to every case:
list.add(new C2(){}); because it could be list = new ArrayList<D1>(); list.add(new D1(){}); because it could be list = new ArrayList<D2>(); and so on.
2. Super
By writing
List<? super C2> list;
you are saying that list will be able to reference an object of type (for example) ArrayList whose generic type is one of the 7 supertypes of C2 ( C2 included):
new ArrayList<A1>(); , (an object that can store A1 or subtypes) or new ArrayList<A2>(); , (an object that can store A2 or subtypes) or new ArrayList<A3>(); , (an object that can store A3 or subtypes) or... and so on. Seven different cases:
1) new ArrayList<A1>(): can store A1 B1 B2 C1 C2 D1 D2 E1 E2 E3 E4
2) new ArrayList<A2>(): can store A2 B2 C1 C2 D1 D2 E1 E2 E3 E4
3) new ArrayList<A3>(): can store A3 B3 C2 C3 D1 D2 E1 E2 E3 E4
4) new ArrayList<A4>(): can store A4 B3 B4 C2 C3 D1 D2 E1 E2 E3 E4
5) new ArrayList<B2>(): can store B2 C1 C2 D1 D2 E1 E2 E3 E4
6) new ArrayList<B3>(): can store B3 C2 C3 D1 D2 E1 E2 E3 E4
7) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4
We have a set of "storable" types for each possible case: 7 (red) sets here graphically represented

As you can see, here we have seven safe types that are common to every case: C2 , D1 , D2 , E1 , E2 , E3 , E4 .
list.add(new C2(){}); because, regardless of the kind of List we're referencing, C2 is allowed list.add(new D1(){}); because, regardless of the kind of List we're referencing, D1 is allowed and so on. You probably noticed that these types correspond to the hierarchy starting from type C2 .
Notes
Here the complete hierarchy if you wish to make some tests
interface A1{}
interface A2{}
interface A3{}
interface A4{}
interface B1 extends A1{}
interface B2 extends A1,A2{}
interface B3 extends A3,A4{}
interface B4 extends A4{}
interface C1 extends B2{}
interface C2 extends B2,B3{}
interface C3 extends B3{}
interface D1 extends C1,C2{}
interface D2 extends C2{}
interface E1 extends D1{}
interface E2 extends D1{}
interface E3 extends D2{}
interface E4 extends D2{}
I love the answer from @Bert F but this is the way my brain sees it.
I have an X in my hand. If I want to write my X into a List, that List needs to be either a List of X or a List of things that my X can be upcast to as I write them in ie any superclass of X...
List<? super X>
If I get a List and I want to read an X out of that List, that better be a List of X or a List of things that can be upcast to X as I read them out, ie anything that extends X
List<? extends X>
Hope this helps.
链接地址: http://www.djcxy.com/p/91976.html上一篇: Java:私有内部类合成构造函数
