• 通过Java反射来理解泛型的本质


      集合框架中经常会使用泛型指定集合中所存放元素的类型,保证集合的统一性,从集合中取出元素的时候也避免了类型强制转换的操作,所以我们使用常规的方式来往集合中存放元素的时候,如果指定泛型,那么我们只能向集合内添加泛型类型的对象,如果不指定泛型,那么可以往集合中添加任何类型的对象,因为此时默认元素是Object类的对象,取出时也需要类型强制转换,就如下面代码:

    1 ArrayList list = new ArrayList();
    2 list.add(1);
    3 list.add("s");    //插入的都是Object的对象类型
    4 System.out.println(list);
    5 
    6 ArrayList<String> list1 = new ArrayList<String>();
    7 list1.add("s");
    8 list1.add(2);    //这是错误的

      这就可以看出泛型的区别,最后一行代码会被编译器报错,下面分别获取list和list1的类类型,并进行比较:

    1 Class c1 = list.getClass();
    2 Class c2 = list1.getClass();
    3 System.out.println(c1 == c2);

      因为list和list1属于两个不同的对象,由此我们推断c1和c2也是不相等的两个类类型,但实际上结果输出true,因为反射获取到类类型相当于字节码的执行阶段,那么c1和c2肯定属于执行阶段的比较,所以我们得到结论:编译之后集合的泛型是去泛型化的,所有的集合类的类类型都相等,泛型就不存在了,泛型只是在编译的时候约束元素的类型,只在编译阶段有效,所以我们可以利用反射的原理,绕过编译,让list1也可以存放不同类型的元素:

     1         try {
     2             Method m = c2.getMethod("add", Object.class);
     3             m.invoke(list1, 100);    //利用反射,在运行阶段执行从而绕过编译的操作
     4             System.out.println(list1.size());
     5             System.out.println(list1);
     6             //不能用foreach来遍历
     7             //用iterator遍历
     8             Iterator it = list1.iterator();
     9             while(it.hasNext()) {
    10                 Object obj1 = it.next();
    11                 System.out.println(obj1);
    12             }
    13             //用for遍历
    14             for(int i = 0;i < list1.size();i++) {
    15                 Object obj2 = list1.get(i);
    16                 System.out.println(obj2);
    17             }
    18         } catch (NoSuchMethodException | SecurityException e) {
    19             e.printStackTrace();
    20         } catch (IllegalAccessException e) {
    21             e.printStackTrace();
    22         } catch (IllegalArgumentException e) {
    23             e.printStackTrace();
    24         } catch (InvocationTargetException e) {
    25             e.printStackTrace();
    26         }

      上面代码通过getMothod方法获得方法对象,然后通过invoke方法来执行方法,这样就可以在带有泛型的集合中存放不同的元素,这样就利用反射绕过了编译的限制;因为无法确定指定方法是否存在,因此需要抛出异常;遍历的时候我们可以使用iterator迭代器或者for循环进行遍历,但是因为类型不一致的原因,所以不能用foreach进行遍历

     

  • 相关阅读:
    MATLAB读取文件——从非常规文本文件中读取数据
    注意——CAN通信设备控制
    硬件——USB传输速度和物理接口
    STM32F4-浮点DSP库的MDK开发环境的设置
    CRC校验
    蓝牙串口使用心得
    Mysql 层级、执行顺序、执行计划分析
    讲一讲垃圾回收算法
    【转】Java中的新生代、老年代、永久代和各种GC
    工具链接
  • 原文地址:https://www.cnblogs.com/freeweb/p/5077876.html
Copyright © 2020-2023  润新知