- 要想Java通过反射越过泛型检查,你就得先明白,泛型是在什么时候起作用的。
- 泛型是在编译期间起作用的。在编译后的.class文件中是没有泛型的。所有比如T或者E类型啊,本质都是通过Object处理的。
- 编译时是调用检查你的源程序是否有语法错误,如果没有就将其翻译成字节码文件。即.class文件。运行时是java虚拟机解释执行字节码文件。即泛型就是那些语法错误的规则。
明白了上面的东西,标题提到的目标也就好实现了。
public class overReflect {
public static void main(String[] args) throws Exception{
ArrayList<Integer> arrayList=new ArrayList<Integer>();
//arrayList.add("索隆");//这样会报错,因为限定必须加入Interger类型的数据
/*
* 那我偏偏想加入字符类型的数据该怎么办呢??
* 这就需要用到我们的反射了。
*/
Class objectClass=arrayList.getClass();
Method method=objectClass.getMethod("add", Object.class);//为什么这里要写Object.class呢??这是 问题一
method.invoke(arrayList, "索隆");
System.out.println(arrayList);
}
}
问题一答案:因为在源代码中是怎么写的。
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {//这里使用E接受的,而E这种底层实现,一般类型都是Object
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
我们都说了这里的E其实是Object,并且泛型是运行在编译期间的,所以它的实现还是像以前那样,都是通过Object接收所有的东西。
那么我们就来反编译看看编译成.class文件后的代码。
居然没有了泛型?? 所以,最终,在ArrayList处理多种数据类型时,还是用的Object接收。代码中常常写的是T或者E。
总结:
因为泛型运行在编译期间,所以反编译.class文件出来的代码是没有带泛型的。而像ArrayList这种能够存储所有类型的数据 类型的容器,底层一般都是用Object实现。即这就是反射能够绕过泛型检查的原因!!