- 前言
Java 1.5 引入了泛型來保證類型安全,防止在運作時發生類型轉換異常,讓類型參數化,提高了代碼的可讀性和重用率。但是有些情況下泛型也是不允許使用的,今天就總結一下編碼中不能使用泛型的一些場景。
- 基本類型無法直接使用泛型
以下寫法是錯誤的:
// error
Map<int,char> wrong= new HashMap<>()
複制代碼
基本類型是不能夠作為泛型類型的,需要使用它們對應的包裝類。
// OK
Map<Integer,Character> wrong= new HashMap<>()
- 泛型類型無法被直接執行個體化
泛型類型可以了解為一個抽象類型,隻是代表了類型的抽象,是以我們不能直接執行個體化它,下面的做法也是錯誤的:
public E first(List list){
// error
E e = new E();
return list.get(0);
}
- 泛型無法作為靜态變量類型
Java 中的靜态類型随着類加載而執行個體化,此時泛型的具體類型并沒有聲明。同時因為靜态變量作為所有對象的共享變量,隻有類執行個體化或者方法調用時才能确定其類型。如果是
手遊賣号泛型類型将無法确定其類型。同樣在類上聲明的泛型也無法作為傳回值類型出現在類的靜态方法中,下面的寫法也是錯誤的:
public class Generic{
// 不能将類聲明的泛型類型作為靜态變量
public static T t;
// 也不能将類聲明的泛型類型作為 靜态方法的傳回值
public static T rtval(List<T> list){
return list.get(0);
}
- 無法進行 instanceof 判斷
Java 中的泛型是僞泛型,在編譯期會被擦除,運作的位元組碼中不存在泛型,是以下面的判斷條件無法進行:
public static void wrong(List list) {
// error
if (list instanceof ArrayList<Integer>) {
}
但是泛型的無界通配符 <?> 可以進行 instanceof 判斷,你仔細想想為什麼。
- 無法建立參數化類型的數組
首先下面這種寫法是對的:
List[] arrayOfLists = new List[2];
但是加上了泛型就編譯不通過了:
//error
如果不這麼規定将引發以下邏輯錯誤:
// 如果上面的成立,則下面的也應該成立
Object[] stringLists = new List[];
// 那麼我們可以放入 字元串 List
stringLists[0] = new ArrayList();
// 放入 Integer list
stringLists[1] = new ArrayList();
// 這顯然不合理
- 不能直接或者間接擴充Throwable
下面的兩種寫法将引發編譯錯誤:
// 不能間接地擴充 Throwable
class IndirectException extends Exception {}
// 不能直接地擴充 Throwable
class DirectException extends Throwable {}
如果成立将出現:
try {
// ...
} catch (T e) {
// 類型不确定 無法處理具體的異常邏輯
}
你如何才能對異常進行具體的處理,這顯然不便于精确的異常處理邏輯。但是你可以抛出一個 不确定的異常,但是同樣不能在靜态方法中使用類聲明的泛型:
class Parser {
// 這樣是對的
public void okThrow(File file) throws T {
// ...
}
// 靜态方法不能出現類聲明的泛型類型作為傳回值和異常
public static void wrongThrow(File file) throws T {
}
- 泛型擦除後相同參數簽名的方法不能重載
由于泛型擦除的原因,以下的不視為方法的重載且無法編譯 :
public class NoReload {
public void sets(Set<String> strSet) { }
public void sets(Set<Integer> intSet) { }
- 總結
今天總結了 Java 泛型的一些使用誤區,雖然平常 IDE 的提示會告訴我們,但是這也是我們經常會忽略的一些知識點。如果有不足之處,請留言指正。如果你想對泛型了解更多,可關注公衆号:碼農小胖哥 回複 generic 擷取相關的學習筆記。