在stackoverflow上看到兩篇關(guān)于java泛型 PECS 的問答:
- Difference between <?super T> and <?extends T> in java
- How can I add to List <?extends Number> data structures
PECS
Remember PECS:"Producer Extends,Consumer Super"
"Producer Extends" - If you need a <code>List</code> to produce <code>T</code> values (you want to read <code>T</code>s from the list), you need to declare it with <code>? extends T</code>, e.g. <code>List<? extends Integer></code>. But you cannot add to this list.
"Consumer Super" - If you need a <code>List</code> to consume <code>T</code> values (you want to write <code>T</code>s into the list), you need to declare it with <code>? super T</code>, e.g. <code>List<? super Integer></code>. 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. <code>List<Integer></code>.
也就是說:
- 當(dāng)你僅僅需要從<code>List</code>中讀出<code>T</code>,那么你需要使用<code>? extends T</code>.例如<code>List<? extends Integer></code>
- 當(dāng)你僅僅需要將T寫入<code>List</code>時匀钧,那么你需要使用<code>? super T</code>.例如<code>List<? super Integer></code>
- 當(dāng)你既需要讀也需要寫時,你應(yīng)該直接使用T. <code>List< Integer></code>
PECS的使用
extends
<code>List<? extends Number> foo</code> 表示<code>foo</code>可以存儲一族的類型的值(而不是一個特殊的類型的值)耕突,所以下面的聲明都是正確的:
List<? extends Number> foo = new ArrayList<Number>; // Number "extends" Number
List<? extends Number> foo = new ArrayList<Integer>; // Integer extends Number
List<? extends Number> foo = new ArrayList<Double>; // Double extends Number
正因為<code>foo</code>表示存儲的是一族的類型的值,無法保證具體指向的類型蔬浙,所以我們無法保證我們<code>add</code>的對象是<code>List</code>允許的類型逗栽。假如我們<code>add</code>一個<code>Integer</code>的值,但是<code>foo</code>可能指向<code>Double</code>(第三條語句)怠晴,我們<code>add</code>一個<code>Double</code>的值,<code>foo</code>可能指向<code>Integer</code>(第二條語句)浴捆。
雖然無法<code>add</code>蒜田,但是我們可以保證我們從<code>foo</code>中取出來的值肯定是屬于<code>Number</code>或者是<code>Number</code>的子類,所以我們可以從<code>foo</code>中獲取值选泻。
super
關(guān)于<code>List<? super T></code>冲粤,以下聲明是正確的:
List<? super Number> foo = new ArrayList<Number>; // Number is a "super" of Number
List<? super Number> foo = new ArrayList<Object>; // Object is a "super" of Number
因為<code>foo</code>的類型無法確定,可能是<code>Number</code>页眯,也可能是<code>Number</code>的父類梯捕,我們無法保證讀出來的值的類型,所以無法從<code>List</code>中讀出值窝撵。但是我們可以保證我們插進去的值肯定屬于<code>Number</code>或者<code>Number</code>的父類傀顾,因此我們可以使用<code>add</code>。
JDK中的例子
<code>Collections.copy()</code>的方法簽名:
public static <T> void copy(List<? super T> dest,List<? extends T> src)
在<code>src</code>中碌奉,我們可以傳入與<code>T</code>類型相關(guān)的<code>List</code>短曾,并且能夠保證取出的是<code>T</code>類型或者<code>T</code>的子類型的值。
在<code>dest</code>中赐劣,我們可以傳入<code>T</code>類型和<code>T</code>的父類的<code>List</code>嫉拐,并且能夠保證我們從存放的值都滿足要求。
例如:
// copy(dest, src)
Collections.copy(new ArrayList<Number>(), new ArrayList<Number());
Collections.copy(new ArrayList<Number>(), new ArrayList<Integer());
Collections.copy(new ArrayList<Object>(), new ArrayList<Number>());
Collections.copy(new ArrayList<Object>(), new ArrayList<Double());
有興趣的同學(xué)可以去看原文魁兼。