原文連結
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>
- 不可以寫
,因為foo3可能指向List<
Number
>
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>
- 不可以讀
,因為List中的元素有可能是指向I
Number
。
List<Object>
- 僅僅可以讀Object類型資料,因為讀出來的資料都可以向上轉型成Object類型。
寫:對于上面三種可能的指派,哪種類型可以保證向List foo3中寫資料?
- 可以寫Integer,因為foo3類型肯定是Integer或者是Integer父類,可以進行向上轉型。
- 可以寫Integer的子類,因為添加Integer子類的元素可以自動向上轉型。
- 不可以寫Double,因為foo3可能指向
ArrayList<Integer>。
- 不可以寫
,因為foo3可能指向
Number
ArrayList<Integer>。
- 不可以寫
,因為foo3可能指向
Object
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
to produceList
values (you want to readT
s from the list), you need to declare it withT
, e.g.? extends T
. But you cannot add to this list.List<? extends Integer>
- "Consumer Super" - If you need a
to consumeList
values (you want to writeT
s into the list), you need to declare it withT
, e.g.? super T
. But there are no guarantees what type of object you may read from this list.List<? super Integer>
- 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>