泛型中的类型擦除

通过反射理解泛型的本质(类型擦除)

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

    }


猜你喜欢

转载自www.cnblogs.com/the-wang/p/10234727.html