zoukankan      html  css  js  c++  java
  • 通过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进行遍历

     

  • 相关阅读:
    2.12 使用@DataProvider
    2.11 webdriver中使用 FileUtils ()
    Xcode8 添加PCH文件
    The app icon set "AppIcon" has an unassigned child告警
    Launch Image
    iOS App图标和启动画面尺寸
    iPhone屏幕尺寸、分辨率及适配
    Xcode下载失败 使用已购项目页面再试一次
    could not find developer disk image
    NSDate与 NSString 、long long类型的相互转化
  • 原文地址:https://www.cnblogs.com/freeweb/p/5077876.html
Copyright © 2011-2022 走看看