標籤:泛型 java
本文主要參考《Java編程思想(第4版)》的Java泛型章節,僅當一個簡單的讀書筆記。
和C++泛型對比,Java泛型只是一種編譯期間的擦拭機制。這是由於考慮到和以前的相容而考慮的一種折中方案。在編譯好的泛型代碼裡,編譯期間已經把所有的泛型資訊給擦拭掉,因此無法獲得任何有關泛型參數類型的資訊。因此List<String>和List<Integer>實際上是同一類型。
參考以下代碼:
//以下3個例子都無法通過編譯 public <T> void testGeneric(Object arg) { if (arg instanceof T) {} //1 T var = new T(); //2 T[] array = new T[100]; //3 }
從以上代碼可以看到,這種擦拭機制的限制包括如下:
1、instanceof無法使用
2、無法執行個體化泛型類
3、無法執行個體化泛型數組
以上3種方法無法通過編譯的主要原因是,泛型的擦拭機制把具體的類型資訊都擦拭,無法在運行時知道確切的類型資訊。不過Java提供了另外的方法去繞過這些限制。
解決1
對於第1種,無法使用instanceof文法,我們可以利用動態isInstance():
//testInstance(String.class, "abc") == true public static <T> boolean testInstance(Class<T> c, Object arg) { return c.isInstance(arg); }<
解決2
對於第2種,無法執行個體化泛型類,如果對於要執行個體化的泛型類,擁有無參預設建構函式,我們可以利用Class對象:
public static <T> T createGeneric(Class<T> c) { T x = null; try { x = c.newInstance(); } catch (Exception e) { throw new RuntimeException(e); //createGeneric<Integer.class>會拋出異常,由於Integer沒有預設建構函式 } return x; } 由於以上代碼採用Class對象執行個體化擁有一定限制,因此我們還可以藉助Factory 方法,顯示建立對應的類:
interface GenericFactory<T> { T create(); } class IntegerFactory implements GenericFactory<Integer> { @Override public Integer create() { return new Integer(0); } }
解決3
對於第3種,無法執行個體化泛型數組,我們可以藉助ArrayList<T>來代替,但如果一定要獲得數組的行為,以及泛型提供的編譯期的安全類型,
//GenericArray ga = new GenericArray<Integer>(10); //ga.put(3, 10); //int abc = (Integer) ga.get(3); //Integer[] aaa = (Integer[]) ga.array(); //拋出ClassCastException class GenericArrayEx<T> { private T[] array; public GenericArray(int size) { array = (T[]) new Object[size]; } public void put(int index, T item) { array[index] = item; } public T get(int index) { return array[index]; } public T[] array() { return array; } } 對於以上代碼,我們採用一個GenericArray的類進行封裝,但內部實際還是一個Object[]的對象數組,在put和get的時候獲得了編譯期間的檢查,但問題來了,如果我們使用array()方法企圖獲得內部數組並轉型的時候,會拋出ClassCastException,這是由於數組實際還是Object[]對象!為瞭解決這個問題,我們可以使用Array.newInstance。
//GenericArrayEx ga = new GenericArrayEx<Integer>(Integer.class, 10); //ga.put(3, 10); //int abc = (Integer) ga.get(3); //Integer[] aaa = (Integer[]) ga.array(); //可以成功轉型 class GenericArrayEx<T> { private T[] array; public GenericArrayEx(Class<T> type, int size) { array = (T[]) Array.newInstance(type, size); } public void put(int index, T item) { array[index] = item; } public T get(int index) { return array[index]; } public T[] array() { return array; } } 這樣,就可以使用T[]了。
Java泛型的一些限制