Java 1.5 引入了泛型來保證類型安全,防止在運行時發生類型轉換異常,讓類型參數化,提升了代碼的可讀性和重用率。可是有些狀況下泛型也是不容許使用的,今天就總結一下編碼中不能使用泛型的一些場景。java
如下寫法是錯誤的:數組
// error
Map<int,char> wrong= new HashMap<>()
複製代碼
基本類型是不可以做爲泛型類型的,須要使用它們對應的包裝類。安全
// OK
Map<Integer,Character> wrong= new HashMap<>()
複製代碼
泛型類型能夠理解爲一個抽象類型,只是表明了類型的抽象,所以咱們不能直接實例化它,下面的作法也是錯誤的:學習
public <E> E first(List<E> list){
// error
E e = new E();
return list.get(0);
}
複製代碼
Java 中的靜態類型隨着類加載而實例化,此時泛型的具體類型並無聲明。同時由於靜態變量做爲全部對象的共享變量,只有類實例化或者方法調用時才能肯定其類型。若是是泛型類型將沒法肯定其類型。一樣在類上聲明的泛型也沒法做爲返回值類型出如今類的靜態方法中,下面的寫法也是錯誤的:編碼
public class Generic<T>{
// 不能將類聲明的泛型類型做爲靜態變量
public static T t;
// 也不能將類聲明的泛型類型做爲 靜態方法的返回值
public static T rtval(List<T> list){
return list.get(0);
}
}
複製代碼
Java 中的泛型是僞泛型,在編譯期會被擦除,運行的字節碼中不存在泛型,因此下面的判斷條件沒法進行:spa
public static <E> void wrong(List<E> list) {
// error
if (list instanceof ArrayList<Integer>) {
}
}
複製代碼
可是泛型的無界通配符
<?>
能夠進行instanceof
判斷,你仔細想一想爲何。3d
首先下面這種寫法是對的:code
// OK
List[] arrayOfLists = new List[2];
複製代碼
可是加上了泛型就編譯不經過了:cdn
//error
List<Integer>[] arrayOfLists = new List<Integer>[2];
複製代碼
若是不這麼規定將引起如下邏輯錯誤:對象
// 若是上面的成立,則下面的也應該成立
Object[] stringLists = new List<String>[];
// 那麼咱們能夠放入 字符串 List
stringLists[0] = new ArrayList<String>();
// 放入 Integer list
stringLists[1] = new ArrayList<Integer>();
// 這顯然不合理
複製代碼
下面的兩種寫法將引起編譯錯誤:
// 不能間接地擴展 Throwable
class IndirectException<T> extends Exception {}
// 不能直接地擴展 Throwable
class DirectException<T> extends Throwable {}
複製代碼
若是成立將出現:
try {
// ...
} catch (T e) {
// 類型不肯定 沒法處理具體的異常邏輯
}
複製代碼
你如何才能對異常進行具體的處理,這顯然不便於精確的異常處理邏輯。可是你能夠拋出一個 不肯定的異常,可是一樣不能在靜態方法中使用類聲明的泛型:
class Parser<T extends Exception> {
// 這樣是對的
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 獲取相關的學習筆記。
關注公衆號:Felordcn獲取更多資訊