在学习java集合的时候,泛型是个很重要的概念,它帮助我们防止了插入集合数据类型出错。在学习java反射的过程中,我们通过集合类对象的类类型进行操作,那么通过这种操作对集合泛型有什么不同?
首先我们创建两个集合对象,其中一个带有泛型String,另一个不带有泛型,插入集合的元素类型不受限制
ArrayList list=new ArrayList();
ArrayList<String> list1=new ArrayList<String>();
list1.add("hello");
则我们现在可以向集合list中添加任意类型对象,而在list1中只能添加String类型的对象,如果我们向list1中加入Integer类型的数据对象,则在编译阶段会出现报错
接下来我们通过类类型和Method来调用ArrayList类中的方法
Class c1=list.getClass();
Class c2=list1.getClass();
System.out.println(c1==c2);
输出结果为:
true
则两个不同泛型的集合对象类型相同,这在我们看来是不合理的,为什么两个不同泛型的对象的类型会相等呢?
这是因为,java的泛型是类型擦除的,即java的泛型在编译阶段是有效的,而在运行阶段会把类型擦除,上述的两个集合对象均变成ArrayList<>,此时比较其类型是相等的。而java的反射操作是在运行阶段进行的,绕过了相应的编译阶段而转换成了字节流,接下类我们来测试一下,java反射操作的执行阶段:
Method m=c2.getMethod("add", Object.class);
m.invoke(list1, 20);
System.out.println(list1.size());
System.out.println(list1);
通过集合的类类型进行方法的调用,这时我们向list1中插入一个int类型的数据,按照泛型的要求,这个操作会在编译阶段发生错误,而运行结果显示:
2
[hello, 20]
插入集合的操作成功进行,说明此时泛型已经被“擦除”,而反射操作在运行时期进行,由此我们可以得出结论:
集合泛型在编译阶段有效,而在运行阶段被“擦除”