通常对于泛型集合我们可以先定义需要添加的元素的类型(如int, String, boolean···),这么一来如果我们添加的元素类型跟预先定义的不一样,则编译不会通过。如
// 声明一个数组列表,里面添加的元素只能是 String
ArrayList<string> list = new ArrayList<>();
// 如果添加的元素是其他类型,如 int
list.add(10);
编译阶段就会出现错误
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method add(int, String) in the type ArrayList<String> is not applicable for the arguments (int)
但是int类型的数据真的添加不了吗?
可以通过反射来达到这个目的,因为反射进行的操作是编译之后的操作,编译之后集合的泛型是去泛型化的。我们就可以通过方法反射,将要添加的数据添加进入集合
// 获取 list 对象的类类型
Class c = list.getClass();
// 获取 add(Object) 方法
Method m = c.getMethod("add", Object.class);
Object obj = m.invoke(list, 10); // 绕过编译就相当于绕过了泛型
这样一来,数据 10 就被添加到集合中去了。
tips: 调用add方法的时候基本数据类型被自动装箱成其对应的对象类型。所以是可以添加进去的
MethodDemo.java
package com.imooc.reflect;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class MethodDemo4 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
ArrayList<String> list1 = new ArrayList<String>();
list1.add("hello");
// list1.add(20); 错误的
Class c1 = list.getClass();
Class c2 = list1.getClass();
System.out.println(c1 == c2);
//反射的操作都是编译之后的操作
/*
* c1==c2结果返回true说明编译之后集合的泛型是去泛型化的
* Java中集合的泛型,是防止错误输入的,只在编译阶段有效,
* 绕过编译就无效了
* 验证:我们可以通过方法的反射来操作,绕过编译
*/
try {
Method m = c2.getMethod("add", Object.class);
m.invoke(list1, 20);//绕过编译操作就绕过了泛型
System.out.println(list1.size());
System.out.println(list1);
/*for (String string : list1) {
System.out.println(string);
}*///现在不能这样遍历
} catch (Exception e) {
e.printStackTrace();
}
}
}