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
-
读 - 若有以上声明,则对List foo3进行读操作时会出现以下情形:
- 可以读取
Number
类型的数据,因为可以赋予foos的列表均包含Number
类型或其子类型的数据。 - 无法读取
Integer
类型的数据,因为foo3可能指向List<Double>
类型的数据。 - 无法读取
Double
类型的数据,因为foo3可能指向List<Integer>
类型的数据。
- 可以读取
-
写 - 若有以上声明,则对List foo3进行写操作(add)时会出现以下情形:
- 无法增添
Integer
类型的数据,因为foo3
可能指向List<Double>
类型的数据。 - 无法增添
Double
类型的数据,因为foo3
可能指向List<Integer>
类型的数据。 - 无法增添
Number
类型的数据,因为foo3
可能指向List<Integer>
类型的数据。
- 无法增添
无法向List<? extends T>
添加任何对象,因为无法保证变量具体指向的是什么类型的List
,从而无法保证目标List
允许添加何种类型的对象。唯一能保证的是可以从中读出一个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
-
读 - 若有以上声明,则对List foo3进行读操作时会出现以下情形:
- 无法读取
Integer
类型的数据,因为foo3可能指向List<Number>
或List<Object>
类型的数据。 - 无法读取
Number
类型的数据,因为foo3可能指向List<Object>
类型的数据。 - 只能读取
Object
类型或Object
子类型的数据(但无法确定是那个子类)。
- 无法读取
-
写 - 若有以上声明,则对List foo3进行写操作(add)时会出现以下情形:
- 可以增添
Integer
类型的数据,因为示例代码中的所有list
均允许增添Integer
类型的数据。 - 可以增添
Integer
子类型的数据,因为示例代码中的所有list
均允许增添Integer
子类型的数据。 - 无法增添
Double
类型的数据,因为foo3可能指向ArrayList<Integer>
类型的数据。 - 无法增添
Number
类型的数据,因为foo3可能指向ArrayList<Integer>
类型的数据。 - 无法增添
Object
类型的数据,因为foo3可能指向ArrayList<Integer>
类型的数据。
- 可以增添
PECS
记住一个口诀: "Producer Extends, Consumer Super"(PECS).
-
"Producer Extends" - 如果一个
List
需要生产T
类型的数据(你想要从list中读取T类型数据),你需要将其声明成? extends T
, e.g.List<? extends Integer>
。但你无法向其中增添数据。 -
"Consumer Super" - 如果你需要一个消费T类型数据的
list
(向其中增添T类型数据),你需要将其声明成? super T
, e.g.List<? super Integer>
。但是你将不知道会从中读取到何种类型的数据。 - 如果你需要从对
List
进行读和写操作,则不要使用通配符式的声明方式,e.g.List<Integer>
。
===> 翻译于StackOverflow