泛型(Generics)簡介
J2SE 5.0中的最顯著的變化之一是添加對泛型類型的支持. 在J2SE 1.4 以及之前的版本中, Java程序并不是類型安全的. 例如, Collection framework中定義的List, Map等容器類的元素都是Object類型, 即這個類包含的元素是Object對象. 使用這種方式實現的列表, 可以用來操作整數, 實數, 字符串或者任何對象類型. 例如
|
這種方法實現的列表需要使用強制類型轉換(又稱顯示造型), 因此不是類型安全的. 在上面這段代碼種, 雖然變量名為stringList, 但是我們仍然可以把一個整型對象添加到這個隊列中, 例如,
清單1.2 類型不安全的代碼示例
|
在這種情況下, 從字符列表中獲取對象時, 強制類型轉換就會導致運行時 異常 .
清單1.3 類型不安全的代碼示例
|
泛型是Java邁向類型安全的一個重要步驟, 使用泛型可以 構造 出類型安全的代碼.
聲明泛型
所謂泛型是指類型參數化(parameterized types). Java是一種強類型的語言, 在J2SE 1.4以及以前的版本中, 我們在定義一個Java類, 接口或者方法的時候, 必須指定變量的類型. 在聲明泛型類、接口或者函數時, 定義變量的時候不指定某些變量的具體類型, 而是用一個類型參數代替. 在使用這個類, 接口, 或者方法的時候, 這個類型參數由一個具體類型所代替.
2.1 泛型類
下面的例子中介紹了如何創建一個最簡單泛型類
清單2.1, 最簡單的泛型類
|
類名后面帶有<T>表明了這個類是泛型類, 其中T被成為類型參數(type parameter), 在使用泛型的時候, 類型參數可以被替換為任何的類類型, 但是不能是原始類型(primitive type), 例如int, double.
下面通過一個列表的例子來具體說明如果聲明泛型類和類型參數的用法.
清單2.2, 泛型列表
|
在列表的例子中, 類型參數T被用來表示列表中的元素的類型, 即, 這個列表中的元素是T類型的.
在使用這個列表時, 這個類型參數T會被具體的類型所替代.
注意, 由于T時類型參數不是具體的類, 所以不能使用new操作符創建T的對象,例如new T(), 或者, new T[10].
2.2 泛型接口
在J2SE 5.0中, 不僅僅可以聲明泛型類, 也可以聲明泛型接口, 聲明泛型接口和聲明泛型類的語法類似, 也是在接口命稱后面加上<T>. 例如,
清單3.2.3, 泛型接口
|
2.3、聲明多個類型參數的泛型類或者接口
在聲明泛型類的時候, 可是使用多個類型參數. 多個類型參數之間用逗號分開, 例如,
清單3.2.4, 多個類型參數的泛型類
|
Eclipse 3.1的類創建向導支持創建泛型類, 如下圖所示,
使用Eclipse接口向導創建泛型接口
2.4 泛型方法
類型參數(type parameter)不僅僅可以用來聲明泛型類或者泛型接口, 也可以用來聲明泛型方法, 而且這種聲明的泛型方法可以用在非泛型類中, 聲明泛型方法的一般格式是
清單2.5 泛型方法的一般形式
|
清單3.2.6 泛型方法示例
|
2.5 受限泛型
受限泛型是指類型參數的取值范圍是受到限制的. extends關鍵字不僅僅可以用來聲明類的繼承關系, 也可以用來聲明類型參數(type parameter)的受限關系.例如, 我們只需要一個存放數字的列表, 包括整數(Long, Integer, Short), 實數(Double, Float), 不能用來存放其他類型, 例如字符串(String), 也就是說, 要把類型參數T的取值泛型限制在Number極其子類中.在這種情況下, 我們就可以使用extends關鍵字把類型參數(type parameter)限制為數字,
清單2.7 受限泛型示例
|
在Eclipse 3.1中, 上例中的編譯錯誤信息如下圖所示
在程序中使用泛型
3.1在程序中使用泛型類
在創建泛型類的對象的時候, 和創建普通對象基本類似, 必須提供具體的類類型來替代類型參數T (J2SE 5.0目前不支持原始類型作為類型參數(type parameter)).
清單3.1, 使用泛型類
|
3.2 使用泛型解決類型安全性問題
使用泛型實現的列表是類型安全的, 下列破壞類型安全語句會在編譯的時候檢查出來。 把鼠標放在錯誤標記上, Eclipse 3.1中的錯誤提示就會顯示,如下圖所示:
3.3 二義性錯誤
GenMap在聲明是使用了2個類型參數T和V, 因此在創建GenMap的對象的時候也需要提供2個具體的類類型來替代這2個類型參數, 例如,
清單9, 多個參數的泛型類
|
上例中, T和V雖然看起來是兩個不同的類型參數, 但是在使用這個泛型類的時候, T和V很有可能被替換成同一種類型. 因此在聲明多個類型參數的泛型類時, 要注意避免這種二義性錯誤, 例如,
清單10, 二義性錯誤
|
在上面這段代碼, 如果T和V被替換成同一種類型, set函數的 簽名 (signature)就是完全一樣的, 所以編譯器會報告二義性錯誤. 正確的用法是聲明2個不同名的方法, 例如,
清單10, 二義性錯誤
|
3.4 使用通配符
前面我們創建了泛型的列表, 如果我需要一個方法來處理泛型列表, 例如, 我們希望把列表中的每個元素都打印出來, 但是類型參數(type parameter)只能使用在聲明一個泛型類的時候, 如果類型參數使用在函數定義里會導致編譯錯誤。
|
在這種情況下, 我們需要用另外一種方法來表示一個泛型類, 否則, 就可能需要書寫多個print函數。
|
J2SE 5.0中提供了泛型的通配符"?", "?"可以用來代替任何類型, 例如使用通配符來實現print方法。
|
泛型的一些局限型
(1) 類型參數不能實例化, 例如,
|
(2) 不能實例化類型參數的數組
|
(3) 類的靜態變量不能聲明為類型參數類型
|
(4) 泛型類不能繼承自Throwable以及其子類
|
泛型小結
泛型是J2SE 5.0所提供的一項強大的功能, 使用泛型可以創建類型安全的、可重用的代碼, 雖然目前Java的泛型還無法和C++的泛型相提并論, 但是, 隨著Java語言本事的演進, 泛型會在Java語言中發揮更大的作用的.
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
