通过Java反射来理解泛型的本质
2015-12-26 12:16
288 查看
集合框架中经常会使用泛型指定集合中所存放元素的类型,保证集合的统一性,从集合中取出元素的时候也避免了类型强制转换的操作,所以我们使用常规的方式来往集合中存放元素的时候,如果指定泛型,那么我们只能向集合内添加泛型类型的对象,如果不指定泛型,那么可以往集合中添加任何类型的对象,因为此时默认元素是Object类的对象,取出时也需要类型强制转换,就如下面代码:
这就可以看出泛型的区别,最后一行代码会被编译器报错,下面分别获取list和list1的类类型,并进行比较:
因为list和list1属于两个不同的对象,由此我们推断c1和c2也是不相等的两个类类型,但实际上结果输出true,因为反射获取到类类型相当于字节码的执行阶段,那么c1和c2肯定属于执行阶段的比较,所以我们得到结论:编译之后集合的泛型是去泛型化的,所有的集合类的类类型都相等,泛型就不存在了,泛型只是在编译的时候约束元素的类型,只在编译阶段有效,所以我们可以利用反射的原理,绕过编译,让list1也可以存放不同类型的元素:
上面代码通过getMothod方法获得方法对象,然后通过invoke方法来执行方法,这样就可以在带有泛型的集合中存放不同的元素,这样就利用反射绕过了编译的限制;因为无法确定指定方法是否存在,因此需要抛出异常;遍历的时候我们可以使用iterator迭代器或者for循环进行遍历,但是因为类型不一致的原因,所以不能用foreach进行遍历
ArrayList list = new ArrayList(); list.add(1); list.add("s"); //插入的都是Object的对象类型 System.out.println(list); ArrayList<String> list1 = new ArrayList<String>(); list1.add("s"); list1.add(2); //这是错误的
这就可以看出泛型的区别,最后一行代码会被编译器报错,下面分别获取list和list1的类类型,并进行比较:
Class c1 = list.getClass(); Class c2 = list1.getClass(); System.out.println(c1 == c2);
因为list和list1属于两个不同的对象,由此我们推断c1和c2也是不相等的两个类类型,但实际上结果输出true,因为反射获取到类类型相当于字节码的执行阶段,那么c1和c2肯定属于执行阶段的比较,所以我们得到结论:编译之后集合的泛型是去泛型化的,所有的集合类的类类型都相等,泛型就不存在了,泛型只是在编译的时候约束元素的类型,只在编译阶段有效,所以我们可以利用反射的原理,绕过编译,让list1也可以存放不同类型的元素:
try { Method m = c2.getMethod("add", Object.class); m.invoke(list1, 100); //利用反射,在运行阶段执行从而绕过编译的操作 System.out.println(list1.size()); System.out.println(list1); //不能用foreach来遍历 //用iterator遍历 Iterator it = list1.iterator(); while(it.hasNext()) { Object obj1 = it.next(); System.out.println(obj1); } //用for遍历 for(int i = 0;i < list1.size();i++) { Object obj2 = list1.get(i); System.out.println(obj2); } } catch (NoSuchMethodException | SecurityException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }
上面代码通过getMothod方法获得方法对象,然后通过invoke方法来执行方法,这样就可以在带有泛型的集合中存放不同的元素,这样就利用反射绕过了编译的限制;因为无法确定指定方法是否存在,因此需要抛出异常;遍历的时候我们可以使用iterator迭代器或者for循环进行遍历,但是因为类型不一致的原因,所以不能用foreach进行遍历
相关文章推荐
- java字符串操作简单总结
- Java中的责任链模式
- MyEclipse和Hadoop上都出现中文乱码问题
- java实现动态代理时遇到的问题
- Eclipse系列: 在Eclipse中用TODO标签管理任务(Task)(ZZ)
- java反射机制和运用
- Spring 4 学习笔记3:依赖注入(DI)
- FreeMarker整合Spring mvc
- java基础02
- Struts2——No result defined for action and result input - action错误
- 深入理解Java内部类
- Java动态加载类在功能模块开发中的作用
- java 死锁产生原因及解锁
- 使用mybatis +spring 插件实现读写分离
- SpringMVC 流程控制(二)
- Spring mvc 统一异常处理和静态文件的配置
- [Maven] - 安装与Eclipse搭建
- 在Java中怎样逐行地写文件?
- spring线程池ThreadPoolExecutor配置并且得到任务执行的结果
- JavaIO流分析总结