List<? super T>和 和有什么不一样List<? extends T>?
List<? super T>
List<? extends T>
我曾经使用过List<? extends T>,但它不允许我向其中添加元素list.add(e),而List<? super T>.
list.add(e)
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:
List foo3
Number
foo3
Integer
List<Double>
Double
List<Integer>
写作* - 鉴于上述可能的分配,您可以添加什么类型的对象对于上述 所有 可能的分配List foo3是合法的: *ArrayList
ArrayList
您不能添加 ,Integer因为foo3可能指向List<Double>。
你不能添加任何对象,List<? extends T>因为你不能保证List它真正指向的是什么类型,所以你不能保证那个对象是允许的List。唯一的“保证”是您只能从中读取,并且您将T获得 T.
List
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:
List<Number>
List<Object>
Object
您可以添加 an,Integer因为Integer在上述任何列表中都允许使用 an。
ArrayList<Integer>
记住 PECS : “生产者扩展,消费者超级” 。
“Producer Extends” - 如果你需要 aList来产生T值(你想T从列表中读取 s),你需要用 来声明它? extends T,例如List<? extends Integer>. 但是您不能添加到此列表中。
? extends T
List<? extends Integer>
“Consumer Super” - 如果你需要 aList来消费T值(你想将Ts 写入列表),你需要用 来声明它? super T,例如List<? super Integer>. 但是不能保证您可以从此列表中读取什么类型的对象。
? super T
List<? super Integer>
如果您需要读取和写入列表,则需要完全声明它,不使用通配符,例如List<Integer>.
请注意Java 泛型常见问题解答中的这个示例。注意源列表src(生产者列表)如何使用extends,目标列表dest(消费列表)如何使用super:
src
dest
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)); } }