JAVA進階之編程大牛告訴你,關於java泛型的那些事

JAVA進階之編程大牛告訴你,關於java泛型的那些事

JAVA進階之編程大牛告訴你,關於java泛型的那些事

JAVA進階之編程大牛告訴你,關於java泛型的那些事

JAVA進階之編程大牛告訴你,關於java泛型的那些事

1,什麼是泛型?

泛型(Generic type 或者 generics)是對 Java 語言的類型系統的一種擴展,以支持創建可以按類型進行參數化的類。可以把類型參數看作是使用參數化類型時指定的類型的一個佔位符,就像方法的形式參數是運行時傳遞的值的佔位符一樣。

可以在集合框架(Collection framework)中看到泛型的動機。例如,Map 類允許您向一個 Map 添加任意類的對象,即使最常見的情況是在給定映射(map)中保存某個特定類型(比如 String)的對象。

因為 Map.get() 被定義為返回 Object,所以一般必須將 Map.get() 的結果強制類型轉換為期望的類型,如下面的代碼所示:

Map m = new HashMap();

m.put("key", "blarg");

String s = (String) m.get("key");

要讓程序通過編譯,必須將 get() 的結果強制類型轉換為 String,並且希望結果真的是一個 String。但是有可能某人已經在該映射中保存了不是 String 的東西,這樣的話,上面的代碼將會拋出 ClassCastException。

理想情況下,您可能會得出這樣一個觀點,即 m 是一個 Map,它將 String 鍵映射到 String 值。這可以讓您消除代碼中的強制類型轉換,同時獲得一個附加的類型檢查層,該檢查層可以防止有人將錯誤類型的鍵或值保存在集合中。這就是泛型所做的工作。

JAVA進階之編程大牛告訴你,關於java泛型的那些事

JAVA進階之編程大牛告訴你,關於java泛型的那些事

2,Java類庫中的泛型

集合類

到目前為止,Java 類庫中泛型支持存在最多的地方就是集合框架。就像容器類是 C++ 語言中模板的主要動機一樣(參閱 附錄 A:與 C++ 模板的比較)(儘管它們隨後用於很多別的用途),改善集合類的類型安全是 Java 語言中泛型的主要動機。集合類也充當如何使用泛型的模型,因為它們演示了泛型的幾乎所有的標準技巧和方言。

所有的標準集合接口都是泛型化的 —— Collection、List、Set 和 Map。類似地,集合接口的實現都是用相同類型參數泛型化的,所以 HashMap 實現 Map 等。

集合類也使用泛型的許多“技巧”和方言,比如上限通配符和下限通配符。例如,在接口 Collection 中,addAll 方法是像下面這樣定義的:

interface Collection {

boolean addAll(Collection extends V>);

}

該定義組合了通配符類型參數和有限制類型參數,允許您將 Collection 的內容添加到 Collection

如果類庫將 addAll() 定義為接受 Collection,您就不能將 Collection

的內容添加到 Collection。不是限制 addAll() 的參數是一個與您將要添加到的集合包含相同類型的集合,而有可能建立一個更合理的約束,即傳遞給 addAll() 的集合的元素 適合於添加到您的集合。有限制類型允許您這樣做,並且使用有限制通配符使您不需要使用另一個不會用在其他任何地方的佔位符名稱。

應該可以將 addAll() 的類型參數定義為 Collection。但是,這不但沒什麼用,而且還會改變 Collection 接口的語義,因為泛型版本的語義將會不同於非泛型版本的語義。這闡述了泛型化一個現有的類要比定義一個新的泛型類難得多,因為您必須注意不要更改類的語義或者破壞現有的非泛型代碼。

作為泛型化一個類(如果不小心的話)如何會更改其語義的一個更加微妙的例子,注意 Collection.removeAll() 的參數的類型是 Collection>,而不是 Collection extends V>。這是因為傳遞混合類型的集合給 removeAll() 是可接受的,並且更加限制地定義 removeAll 將會更改方法的語義和有用性。

其他容器類

除了集合類之外,Java 類庫中還有幾個其他的類也充當值的容器。這些類包括 WeakReference、SoftReference 和 ThreadLocal。它們都已經在其包含的值的類型上泛型化了,所以 WeakReference

是對 T 類型的對象的弱引用,ThreadLocal 則是到 T 類型的線程局部變量的句柄。

泛型不止用於容器

泛型最常見最直觀的使用是容器類,比如集合類或引用類(比如 WeakReference)。Collection 中類型參數的含義很明顯 —— “一個所有值都是 V 類型的集合”。類似地,ThreadLocal 也有一個明顯的解釋 —— “一個其類型是 T 的線程局部變量”。但是,泛型規格說明中沒有指定容積。

像 Comparable 或 Class 這樣的類中類型參數的含義更加微妙。有時,就像 Class 中一樣,類型變量主要是幫助編譯器進行類型推理。有時,就像隱含的 Enum> 中一樣,類型變量只是在類層次結構上加一個約束。

JAVA進階之編程大牛告訴你,關於java泛型的那些事

JAVA進階之編程大牛告訴你,關於java泛型的那些事

Comparable

Comparable 接口已經泛型化了,所以實現 Comparable 的對象聲明它可以與什麼類型進行比較。(通常,這是對象本身的類型,但是有時也可能是父類。)

public interface Comparable {

public boolean compareTo(T other);

}

所以 Comparable 接口包含一個類型參數 T,該參數是一個實現 Comparable 的類可以與之比較的對象的類型。這意味著如果定義一個實現 Comparable 的類,比如 String,就必須不僅聲明類支持比較,還要聲明它可與什麼比較(通常是與它本身比較):

public class String implements Comparable { ... }

JAVA進階之編程大牛告訴你,關於java泛型的那些事

JAVA進階之編程大牛告訴你,關於java泛型的那些事

歡迎大家在下方積極吐槽,小編會一一進行查看並回復,期待你的答案哦……

如果喜歡請轉發,小小支持一下。


分享到:


相關文章: