通过Class,Method来认识泛型的本质
我们知道Java中集合的泛型是防止错误输入的,例如ArrayList<String>list1=new ArrayList<String>();
接下来如果再有list1.add(20);
系统便提示错误,程序无法通过编译,以为list1的类型已被指定为String,那么我们看以下代码
Class c1=list.getClass();
Class c2=list1.getClass();
System.out.println(c1==c2);
此时系统输出的是却是true,未使用泛型的list和使用泛型指定唯一类型String的list1具有相同的类类型(getClass()方法返回类的类类型)吗??
原因在于——泛型只在编译阶段有效,编译完成后自动去泛型化,而反射操作都是编译之后的操作,下面我们举例加深理解。
package 反射与泛型;
import java.lang.reflect.Method;
import java.util.*;
public class Example {
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());
} catch (Exception e) {
e.printStackTrace();
}
}
}
很显然,我们成功地使用反射绕过了泛型为list1添加了一个int类型的元素20,说明绕过绕过编译操作也就绕过了泛型。
总结
此刻,我们对于泛型和反射有了一定的认识,但是编译过程到底是如何实现的,底层类的加载执行又有哪些细节,还有待于深入学习。