泛型中的類型擦除
阿新 • • 發佈:2019-01-08
泛型 add args 參數類型 一份 ack color div list
通過反射理解泛型的本質(類型擦除)
Java中的泛型是通過類型擦除來實現的。所謂類型擦除,是指通過類型參數合並,將泛型類型實例關聯到同一份字節碼上。編譯器只為泛型類型生成一份字節碼,並將其實例關聯到這份字節碼上。類型擦除的關鍵在於從泛型類型中清除類型參數的相關信息,並且再必要的時候添加類型檢查和類型轉換的方法。
下面通過兩個例子來證明在編譯時確實發生了類型擦除。
例1分別創建實際類型為String和Integer的ArrayList對象,通過getClass()方法獲取兩個實例的類,最後判斷這個實例的類是相等的,證明兩個實例共享同一個類。
// 聲明一個具體類型為String的ArrayListArrayList<String> arrayList1 = new ArrayList<String>(); arrayList1.add("abc"); // 聲明一個具體類型為Integer的ArrayList ArrayList<Integer> arrayList2 = new ArrayList<Integer>(); arrayList2.add(123); System.out.println(arrayList1.getClass() == arrayList2.getClass()); // 結果為true
例2創建一個只能存儲Integer的ArrayList對象,
1、正常添加Integer
2、使用Object.class 作為參數類型,利用反射添加 Integer , 利用反射添加 String
3、以Integer.class 作為參數類型, 利用反射添加Integer , NoSuchMethodException
說明編譯後的泛型中只保留了 Object 作為參數類型,擦除了Integer 這個泛型信息。
說明泛型只是為了防止輸入出錯,只在編譯期有用,可以利用反射繞過編譯期。
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { ArrayList<Integer> arrayList3 = new ArrayList<Integer>(); arrayList3.add(1); // arrayList3.getClass().getMethod("add", Object.class).invoke(arrayList3, "一"); System .out.println("輸出一:"); for (int i = 0; i < arrayList3.size(); i++) { System.out.println(arrayList3.get(i)); // 輸出 } arrayList3.getClass().getMethod("add", Object.class).invoke(arrayList3, 2); // 使用Object.class 可以add Integer arrayList3.getClass().getMethod("add", Object.class).invoke(arrayList3, "二"); // 使用Object.class 可以add String System.out.println("輸出二:"); for (int i = 0; i < arrayList3.size(); i++) { System.out.println(arrayList3.get(i)); // 輸出 } System.out.println("輸出三:"); arrayList3.getClass().getMethod("add", Integer.class).invoke(arrayList3, 3); // 使用Integer.class NoSuchMethodException:java }
泛型中的類型擦除