泛型中<? extends T>和<? super T>差別

泛型中<? extends T>和<? super T>差別

????????<? extends T?和<? super T>含有JAVA5.0的新的概念。由于它們的外表導(dǎo)致了很多人誤解了它們的用途:

????????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)可以呢?因為能放入某一類的容器一定可以放入其子類,多態(tài)的概念。擦除也許泛型最具挑戰(zhàn)性的方面是擦除(erasure),這是 Java語言中泛型實現(xiàn)的底層技術(shù)。擦除意味著編譯器在生成類文件時基本上會拋開參數(shù)化類的大量類型信息。編譯器用它的強制類型轉(zhuǎn)換生成代碼,就像程序員在泛型出現(xiàn)之前手工所做的一樣。區(qū)別在于,編譯器開始已經(jīng)驗證了大量如果沒有泛型就不會驗證的類型安全約束。通過擦除實現(xiàn)泛型的含意是很重要的,并且初看也是混亂的。盡管不能將List賦給List,因為它們是不同的類型,但是List<Integer>和 List<Number>類型的變量是相同的類!要明白這一點,請評價下面的代碼:

????new List<Number>().getClass() == new List<Integer>().getClass()

????????編譯器只為 List 生成一個類。當(dāng)生成了 List 的字節(jié)碼時,將很少剩下其類型參數(shù)的的跟蹤。當(dāng)生成泛型類的字節(jié)碼時,編譯器用類型參數(shù)的擦除替換類型參數(shù)。對于無限制類型參數(shù)(<V>),它的擦除是Object。對于上限類型參數(shù)(<K extends Comparable<K>>),它的擦除是其上限(在本例中是Comparable)的擦除。對于具有多個限制的類型參數(shù),使用其最左限制的擦除。如果檢查生成的字節(jié)碼,您無法說出 List<Integer>和 List<String>的代碼之間的區(qū)別。類型限制 T 在字節(jié)碼中被 T 的上限所取代,該上限一般是 Object。

多重限制:

????????一個類型參數(shù)可以具有多個限制。當(dāng)您想要約束一個類型參數(shù)比如說同時為 Comparable 和 Serializable 時,這將很有用。多重限制的語法是用“與”符號分隔限制:

class C<T extends Comparable<? super T>&Serializable>通配符類型可以具有單個限制 —— 上限或者下限。一個指定的類型參數(shù)可以具有一個或多個上限。具有多重限制的類型參數(shù)可以用于訪問它的每個限制的方法和域。類型形參和類型實參在參數(shù)化類的定義中,占位符名稱(比如 Collection<V>中的 V)叫做類型形參(typeparameter),它們類似于方法定義中的形式參數(shù)。在參數(shù)化類的變量的聲明中,聲明中指定的類型值叫做類型實參(type argument),它們類似于方法調(diào)用中的實際參數(shù)。但是實際中二者一般都通稱為“類型參數(shù)”。所以給出定義:

interface Collection<V>{ ... }和聲明:Collection<String> cs = new HashSet<String>(); 那么,名稱 V(它可用于整個 Collection 接口體內(nèi))叫做一個類型形參。在 cs 的聲明中,String 的兩次使用都是類型實參(一次用于 Collection<V>,另一次用于 HashSet<V>)。

關(guān)于何時可以使用類型形參,存在一些限制。大多數(shù)時候,可以在能夠使用實際類型定義的任何地方使用類型形參。但是有例外情況。不能使用它們創(chuàng)建對象或數(shù)組,并且不能將它們用于靜態(tài)上下文中或者處理異常的上下文中。還不能將它們用作父類型(class Foo<T> extends T),不能用于 instanceof 表達(dá)式中,不能用作類常量。類似地,關(guān)于可以使用哪些類型作為類型實參,也存在一些限制。類型實參必須是引用類型(不是基本類型)、通配符、類型參數(shù),或者其他參數(shù)化類型的實例化。所以您可以定義List<String>(引用類型)、List<?>(通配符)或者List<List<?>>(其他參數(shù)化類型的實例化)。在帶有類型形參 T 的參數(shù)化類型的定義中,您也可以聲明List<T>(類型形參)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容