List<? super T>
and List<? extends T>之间有什么区别呢?
我可以常常在List<? super T>中使用add,但是无法对List<? extends T>使用add,这是为啥?
Case1:List<? extends T>
对泛型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,因为List中所有的元素都是Number的子类,自动向上转型。
- 不可以读Integer,因为List中的元素有可能是指向Double类型的。
- 不可以读Double,因为List中的元素有可能是指向Integer类型的。
写:对于上面三种可能的赋值,哪种类型可以保证向List foo3中写数据?
- 不可以写Integer,因为foo3可能指向List<Double>
- 不可以写Double,因为foo3可能指向List<Integer>
- 不可以写
Number
,因为foo3可能指向List<Integer
>
不能将任何对象添加到List<?extends T>,因为不能保证它真正指向什么类型的列表。唯一的“保证”是只能从中读取得到一个T或T的子类。
Case2: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,因为List中的元素有可能是指向
List<Number>
或者List<Object>
。- 不可以读
Number
,因为List中的元素有可能是指向IList<Object>
。- 仅仅可以读Object类型数据,因为读出来的数据都可以向上转型成Object类型。
写:对于上面三种可能的赋值,哪种类型可以保证向List foo3中写数据?
- 可以写Integer,因为foo3类型肯定是Integer或者是Integer父类,可以进行向上转型。
- 可以写Integer的子类,因为添加Integer子类的元素可以自动向上转型。
- 不可以写Double,因为foo3可能指向
ArrayList<Integer>。
- 不可以写
Number
,因为foo3可能指向ArrayList<Integer>。
- 不可以写
Object
,因为foo3可能指向ArrayList<Integer>。
总结:
- List<?> : 可以接受任何类型的集合引用赋值,不能添加任何元素,但是可以remove和clear
- List<? extend T>:get first,只能取,取出来向上转为T,除了null,任何元素都不能往里面放
- List<? super T>:put first,只能放入T及其子类,能够取出数据,但是类型会丢失,只能返回Object对象
PECS
PECS: "Producer Extends, Consumer Super".
-
"Producer Extends" - If you need a
List
to produceT
values (you want to readT
s from the list), you need to declare it with? extends T
, e.g.List<? extends Integer>
. But you cannot add to this list. -
"Consumer Super" - If you need a
List
to consumeT
values (you want to writeT
s into the list), you need to declare it with? super T
, e.g.List<? super Integer>
. But there are no guarantees what type of object you may read from this list. -
If you need to both read from and write to a list, you need to declare it exactly with no wildcards, e.g.
List<Integer>
.