通过反射理解泛型的本质(类型擦除)
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 }
原文地址:https://www.cnblogs.com/the-wang/p/10234727.html
时间: 2024-10-29 13:10:10