<?之间的区别 超级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