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