<?之间的区别 超级T>和<? 在Java中扩展T>
List<? super T>什么区别List<? super T> List<? super T>和List<? extends T> List<? extends T> ?
我曾经使用List<? extends T> List<? extends T> ,但它不允许我添加元素给它list.add(e) ,而List<? super T> List<? super T> 。
extends
List<? extends Number> foo3的通配符声明 List<? extends Number> foo3意味着任何这些都是合法的作业:
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
阅读 - 鉴于上述可能的任务,你保证从List foo3读取什么类型的对象:
Number ,因为任何可能被分配到列表中的foo3含有Number或子类Number 。 Integer因为foo3可能指向List<Double> 。 Double因为foo3可能指向List<Integer> 。 写作 - 给定上述可能的赋值,可以将List foo3类型的对象添加到List foo3 ,这对于所有上述可能的ArrayList赋值都是合法的:
Integer因为foo3可能指向List<Double> 。 Double因为foo3可能指向List<Integer> 。 Number因为foo3可能指向一个List<Integer> 。 你不能添加任何对象到List<? extends T> List<? extends T>因为你不能保证它真正指向什么样的List ,所以你不能保证该List允许该对象。 唯一的“保证”是,你只能从它读,你会得到一个T的或子类T 。
super
现在考虑List <? super T> List <? super T> 。
List<? super Integer> foo3的通配符声明 List<? super Integer> foo3意味着这些都是合法的任务:
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
阅读 - 考虑到上述可能的任务,当您从List foo3读取时,您保证会收到什么类型的对象:
Integer因为foo3可能指向List<Number>或List<Object> 。 Number因为foo3可能指向一个List<Object> 。 Object或子类Object (但你不知道什么是子类)。 写作 - 给定上述可能的赋值,可以将List foo3类型的对象添加到List foo3 ,这对于所有上述可能的ArrayList赋值都是合法的:
Integer因为在上面的任何列表中都允许有Integer 。 Integer子类的实例,因为在上述任何一个列表中都允许有一个Integer子类的实例。 Double因为foo3可能指向ArrayList<Integer> 。 Number因为foo3可能指向一个ArrayList<Integer> 。 Object因为foo3可能指向一个ArrayList<Integer> 。 佩奇
记住PECS: “生产者延伸,消费者超级” 。
“Producer Extends” - 如果你需要一个List来产生T值(你想从列表中读取T s),你需要用? extends T ? extends T ,例如List<? extends Integer> List<? extends Integer> 。 但是你不能添加到这个列表中。
“消费者超级” - 如果您需要一个List来消费T值(您想将T s写入列表中),您需要声明它? super T ? super T ,例如List<? super Integer> List<? super Integer> 。 但是不能保证你可以从这个列表中读取什么类型的对象。
如果你需要读取和写入列表,你需要声明它完全没有通配符,例如List<Integer> 。
例
请注意Java泛型常见问题中的这个例子。 注意源列表src (生产列表)使用的extends ,目标列表dest (消费列表)使用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));
}
}
另请参阅如何添加到List <? 扩展Number>数据结构?
想象一下这个层次结构

1.延长
通过写作
List<? extends C2> list;
您是说, list将能够引用类型(例如)的目的ArrayList其一般类型是的7种亚型之一C2 ( C2附带):
new ArrayList<C2>(); ,(可以存储C2或子类型的对象)或 new ArrayList<D1>(); ,(可以存储D1或子类型的对象)或 new ArrayList<D2>(); ,(可以存储D2或子类型的对象)或... 等等。 七种不同的情况:
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
对于每种可能的情况,我们都有一组“可存储”类型:这里用图形表示7(红色)

正如你所看到的,没有一种安全类型对于每一种情况都是常见的:
list.add(new C2(){}); 因为它可能是list = new ArrayList<D1>(); list.add(new D1(){}); 因为它可能是list = new ArrayList<D2>(); 等等。
2.超级
通过写作
List<? super C2> list;
您是说, list将能够引用类型(例如)的目的ArrayList其一般类型是的7个超类型之一C2 ( C2附带):
new ArrayList<A1>(); ,(可存储A1或子类型的对象)或 new ArrayList<A2>(); ,(可以存储A2或子类型的对象)或 new ArrayList<A3>(); ,(可以存储A3或子类型的对象)或... 等等。 七种不同的情况:
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
对于每种可能的情况,我们都有一组“可存储”类型:这里用图形表示7(红色)

正如你所看到的,这里我们有七种安全类型,它们在每种情况下都是通用的: C2 , D1 , D2 , E1 , E2 , E3 , E4 。
list.add(new C2(){}); 因为无论我们引用的List是什么类型, C2都是允许的 list.add(new D1(){}); 因为无论我们引用的List是什么类型, D1都是允许的 等等。 您可能注意到这些类型与从C2类型开始的层次结构相对应。
笔记
这里是完整的层次结构,如果你想做一些测试
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{}
我喜欢@Bert F的回答,但这是我的大脑看到它的方式。
我手里有一个X. 如果我想将我的X写入一个List,那么这个List需要是X的列表或X的列表,我可以在X中写入它们的任何超类 ...
List<? super X>
如果我得到一个列表,并且我想从列表中读取一个X,那么最好是X列表或X列表,当我将它们读出时,它们可以上传到X,即任何扩展 X
List<? extends X>
希望这可以帮助。
链接地址: http://www.djcxy.com/p/91975.html上一篇: Difference between <? super T> and <? extends T> in Java
