泛型中<? extends T>和<? super T> 差異程序員
<? extends T>和<? super T>含有JAVA5.0的新的概念。因爲它們的外表致使了不少人誤解了它們的用途:數組
1.<? extends T>首先你很容易誤解它爲繼承於T的全部類的集合,這是大錯特錯的,相信能看下去你必定見過或用過List<? extends T>吧?爲何我說理解成一個集合是錯呢?若是理解成一個集合那爲何不用List<T>來表示?因此<? extends T>不是一個集合,而是T的某一種子類的意思,記住是一種,單一的一種,問題來了,因爲連哪種都不肯定,帶來了不肯定性,因此是不可能經過 add()來加入元素。你或許還以爲爲何add(T)不行? 由於<? extends T>是T的某種子類,能放入子類的容器不必定能放入超類,也就是沒可能放入T。安全
2.<? super T>這裏比較容易使用,沒<? extends T>這麼多限制,這裏的意思是,以T類爲下限的某種類,簡單地說就是T類的超類。但爲何add(T)能夠呢?由於能放入某一類的容器必定能夠放入其子類,多態的概念。spa
擦除對象
也許泛型最具挑戰性的方面是擦除(erasure),這是 Java 語言中泛型實現的底層技術。擦除意味着編譯器在生成類文件時基本上會拋開參數化類的大量類型信息。編譯器用它的強制類型轉換生成代碼,就像程序員在泛型出現以前手工所作的同樣。區別在於,編譯器開始已經驗證了大量若是沒有泛型就不會驗證的類型安全約束。繼承
經過擦除實現泛型的含義是很重要的,而且初看也是混亂的。儘管不能將List<Integer> 賦給List<Number>,由於它們是不一樣的類型,可是 List<Integer> 和 List<Number> 類型的變量是相同的類!要明白這一點,請評價下面的代碼:接口
new List<Number>().getClass() == new List<Integer>().getClass()get
編譯器只爲 List 生成一個類。當生成了 List 的字節碼時,將不多剩下其類型參數的的跟蹤。編譯器
當生成泛型類的字節碼時,編譯器用類型參數的擦除替換類型參數。對於無限制類型參數(<V>),它的擦除是 Object。對於上限類型參數(<K extends Comparable<K>>),它的擦除是其上限(在本例中是 Comparable)。對於具備多個限制的類型參數,使用其最左限制的擦除。io
若是檢查生成的字節碼,您沒法說出 List<Integer> 和 List<String> 的代碼之間的區別。類型限制 T 在字節碼中被 T 的上限所取代,該上限通常是 Object。
多重限制
一個類型參數能夠具備多個限制。當您想要約束一個類型參數好比說同時爲 Comparable 和 Serializable 時,這將頗有用。多重限制的語法是用「與」符號分隔限制:
class C<T extends Comparable<? super T>&Serializable>
通配符類型能夠具備單個限制 —— 上限或者下限。一個指定的類型參數能夠具備一個或多個上限。具備多重限制的類型參數能夠用於訪問它的每一個限制的方法和域。
類型形參和類型實參
在參數化類的定義中,佔位符名稱(好比 Collection<V> 中的 V)叫作類型形參(type parameter),它們相似於方法定義中的形式參數。在參數化類的變量的聲明中,聲明中指定的類型值叫作類型實參(type argument),它們相似於方法調用中的實際參數。可是實際中兩者通常都通稱爲「類型參數」。因此給出定義:
interface Collection<V> { ... }
和聲明:
Collection<String> cs = new HashSet<String>();
那麼,名稱 V(它可用於整個 Collection 接口體內)叫作一個類型形參。在 cs 的聲明中,String 的兩次使用都是類型實參(一次用於 Collection<V>,另外一次用於 HashSet<V>)。
關於什麼時候可使用類型形參,存在一些限制。大多數時候,能夠在可以使用實際類型定義的任何地方使用類型形參。可是有例外狀況。不能使用它們建立對象或數組,而且不能將它們用於靜態上下文中或者處理異常的上下文中。還不能將它們用做父類型(class Foo<T> extends T),不能用於 instanceof 表達式中,不能用做類常量。
相似地,關於可使用哪些類型做爲類型實參,也存在一些限制。類型實參必須是引用類型(不是基本類型)、通配符、類型參數,或者其餘參數化類型的實例化。因此您能夠定義 List<String>(引用類型)、List<?>(通配符)或者 List<List<?>>(其餘參數化類型的實例化)。在帶有類型形參 T 的參數化類型的定義中,您也能夠聲明 List<T>(類型形參)。