List<? super T>
和List<? extends T>
有什么区别?
我过go 使用List<? extends T>
,但它不允许我向其添加元素list.add(e)
,而List<? super T>
可以.
List<? super T>
和List<? extends T>
有什么区别?
我过go 使用List<? extends T>
,但它不允许我向其添加元素list.add(e)
,而List<? super T>
可以.
扩展
通配符声明为List<? 扩展 Number> foo3
意味着其中任何一项都是合法转让:
List<? 扩展 Number> foo3 = new ArrayList<Number>(); // Number "扩展" Number (in this context)
List<? 扩展 Number> foo3 = new ArrayList<Integer>(); // Integer 扩展 Number
List<? 扩展 Number> foo3 = new ArrayList<Double>(); // Double 扩展 Number
Reading-鉴于上述可能的赋值,你保证从List foo3
中读取什么类型的对象:
foo3
的任何列表都包含Number
或Number
的子类.Integer
,因为foo3
可能指向List<Double>
.Double
,因为foo3
可能指向List<Integer>
.Writing-鉴于上述可能的转让,您可以在List foo3
中添加哪种类型的物品,这对于all上述可能的ArrayList
转让是合法的:
Integer
,因为foo3
可能指向List<Double>
.Double
,因为foo3
可能指向List<Integer>
.Number
,因为foo3
可能指向List<Integer>
.You can't add any object to 100 because you can't guarantee what kind of 101 it is really pointing to, so you can't guarantee that the object is allowed in that 101. The only "guarantee" is that you can only read from it and you'll get a 103 or subclass of 103.
超级的
现在考虑List <? 超级的 T>
个.
通配符声明List<? 超级的 Integer> foo3
表示其中任何一个都是合法分配:
List<? 超级的 Integer> foo3 = new ArrayList<Integer>(); // Integer is a "超级的class" of Integer (in this context)
List<? 超级的 Integer> foo3 = new ArrayList<Number>(); // Number is a 超级的class of Integer
List<? 超级的 Integer> foo3 = new ArrayList<Object>(); // Object is a 超级的class of Integer
Reading-鉴于上述可能的分配,当你阅读List foo3
时,你保证会收到什么类型的对象:
Integer
分,因为foo3
可能指向List<Number>
或List<Object>
.Number
分,因为foo3
可能指的是List<Object>
分.Object
的子类(但是您不知道是哪个子类).Writing-鉴于上述可能的转让,您可以在List foo3
中添加哪种类型的物品,这对于all上述可能的ArrayList
转让是合法的:
Integer
,因为上述任何列表中都允许使用Integer
.Integer
子类的实例,因为在上述任何列表中都允许Integer
子类的实例.Double
,因为foo3
可能指向ArrayList<Integer>
.Number
,因为foo3
可能指向ArrayList<Integer>
.Object
,因为foo3
可能指向ArrayList<Integer>
.记住佩克斯:"Producer Extends, Consumer Super".
"Producer Extends"-如果你需要一个List
来产生T
个值(你想从列表中读取T
),你需要用? 扩展 T
来声明它,例如List<? 扩展 Integer>
.但是你不能添加到这个列表中.
"Consumer Super"-如果您需要List
来使用T
个值(您想要将T
写入列表),则需要用? 超级的 T
来声明它,例如List<? 超级的 Integer>
.但不能保证您可以从此列表中读取哪种类型的对象.
如果需要对列表进行读写操作,则需要准确地声明列表,不使用通配符,例如List<Integer>
.
注this example from the Java Generics FAQ.注意源列表src
(生产列表)如何使用扩展
,目的地列表dest
(消费列表)如何使用超级的
:
public class Collections {
public static <T> void copy(List<? 超级的 T> dest, List<? 扩展 T> src) {
for (int i = 0; i < src.size(); i++)
dest.set(i, src.get(i));
}
}
也看到