1. 程式人生 > >泛型中的型別擦除

泛型中的型別擦除

通過反射理解泛型的本質(型別擦除)

Java中的泛型是通過型別擦除來實現的。所謂型別擦除,是指通過型別引數合併,將泛型型別例項關聯到同一份位元組碼上。編譯器只為泛型型別生成一份位元組碼,並將其例項關聯到這份位元組碼上。型別擦除的關鍵在於從泛型型別中清除型別引數的相關資訊,並且再必要的時候新增型別檢查和型別轉換的方法。

下面通過兩個例子來證明在編譯時確實發生了型別擦除。

例1分別建立實際型別為String和Integer的ArrayList物件,通過getClass()方法獲取兩個例項的類,最後判斷這個例項的類是相等的,證明兩個例項共享同一個類。

// 宣告一個具體型別為String的ArrayList
ArrayList<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 }