extends
通配符声明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
-
Reading- 鉴于上述可能的分配,您保证读取什么类型的对象List foo3
:
- 您可以阅读
Number
因为任何可以分配给的列表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>
.
您无法添加任何对象List<? extends T>
因为你不能保证什么样的List
它确实指向,所以你不能保证该对象是允许的List
。唯一的“保证”是你只能从中读取,并且你会得到一个T
或子类T
.
super
现在考虑List <? super T>
.
通配符声明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
-
Reading- 鉴于上述可能的分配,当您读取时保证收到什么类型的对象List foo3
:
- 不保证您
Integer
因为foo3
可能指着一个List<Number>
or List<Object>
.
- 不保证您
Number
因为foo3
可能指着一个List<Object>
.
- The only保证你会得到一个实例
Object
或子类Object
(但你不知道是什么子类)。
-
Writing- 鉴于上述可能的分配,您可以添加什么类型的对象List foo3
这将是合法的all以上可能的ArrayList
作业:
- 您可以添加一个
Integer
因为一个Integer
允许出现在上述任何列表中。
- 您可以添加子类的实例
Integer
因为子类的实例Integer
允许出现在上述任何列表中。
- 你不能添加一个
Double
因为foo3
可能指着一个ArrayList<Integer>
.
- 你不能添加一个
Number
因为foo3
可能指着一个ArrayList<Integer>
.
- 您无法添加
Object
因为foo3
可能指着一个ArrayList<Integer>
.
PECS
记住PECS: “生产者延伸,消费者超”.
《生产者延伸》- 如果您需要List
生产T
值(你想读T
列表中的 s),您需要使用以下方式声明它? extends T
, e.g. List<? extends Integer>
。但您无法添加到此列表中。
《消费超级》- 如果您需要List
消费T
值(你想写T
s 进入列表),你需要声明它? super T
, e.g. List<? super Integer>
。但不能保证您可以从此列表中读取哪种类型的对象。
如果您需要读取和写入列表,则需要准确声明它,不带通配符,例如List<Integer>
.
Example
Note 此示例来自 Java 泛型常见问题解答 http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ103。注意源列表的方式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));
}
}
另请参阅如何添加到列表 数据结构? https://stackoverflow.com/questions/2776975/how-can-i-add-to-list-extends-number-data-structures/2777297#2777297