zoukankan      html  css  js  c++  java
  • Java-Reflection反射-获取包括父类在内的所有字段

    Java-Reflection反射-获取包括父类在内的所有字段

    前言

    今天Android移动端要加个新功能,所以回归Android程序员的身份.开发的过程中,发现了之前的代码写的有很多问题,真的应该把时间抽出来重构一下了.

    其中有反射的一个坑,工具类某方法反射获取传入Model的属性值.但是当我把公共属性抽出来做基类的时候,发现获取不到基类的属性值了.原因是使用了getDeclaredFields();

    分析

    方法功能
    getFields() 获取所有public字段,包括父类字段
    getDeclaredFields() 获取所有字段,public和protected和private,但是不包括父类字段

    写个小方法验证一下下~

    写两个类,里面定义三个字段,分别用public,protected,private修饰, 
    一个叫ParentModel,作为父类. 
    一个叫model,继承ParentModel

    /**
     * 用作父类
     */
    public class ParentModel {
    
        private String p_privateField;
        public String p_publicField;
        protected  String p_protectedField;
    }
    /**
     * 子类,继承上面定义的用作父类的ParentModel
     */
    public class Model extends ParentModel{
    
        private String privateField;
        public String publicField;
        protected  String protectedField;
    
    }

    ok,分别使用getFields()和getDeclaredFields()获取model的字段,循环打印出来.

     Field[] fs = Model.class.getFields();
     Field[] fs1 = Model.class.getDeclaredFields();
     for (Field f:fs) {          
         Log.d("getFields","getFields---"+f.getName());
     }
    
     for (Field f:fs1) {           
         Log.d("getDeclaredFields","getDeclaredFields---"+f.getName());
     }

    见证答案的时候到了~ 
    getFields()的打印输出:

    这里写图片描述

    getDeclaredFields()的打印输出:

    这里写图片描述

    测试证实了我们上面的结论是对的.

    我想获取子类和父类的所有Field

    如果想用反射通过Model获取parentModel和Model的所有字段,怎么办?很明显上面的两个方法都是满足不了的.那怎么办?

    不用怕,我们递归Model的父类去getDeclaredFields(),代码如下:

    List<Field> fieldList = new ArrayList<>() ;
    Class tempClass = Model.class;
    while (tempClass != null) {//当父类为null的时候说明到达了最上层的父类(Object类).
          fieldList.addAll(Arrays.asList(tempClass .getDeclaredFields()));
          tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
    }
    for (Field f : fieldList) {
    
        Log.d("getAllFields","getFields---"+f.getName());
    }

    这里写图片描述

    可以看到我们获取了Model和ParentModel的全部字段,不仅如此,还多出来了两个字段shadow$_klass_ 和shadow_monitor_,这个是Object中的字段.

    shadow$_monitor_shadow$_klass_是Android sdk21之后Object增加的两个字段。

    如果你想屏蔽Object类的影响,可以为while循环再添加一个条件:

    while (tmpClass !=null && !tmpClass.getName().toLowerCase().equals("java.lang.object") )
    {
          ....
    }

    更新说明

    2017.6.27更新:

    之前被网友 lucky_god88 指出博客反射获取的值和真实情况不符,核实之后,已经更正为正确答案,这里谢谢可爱的lucky_god88 发现并给我指出问题,解决问题的同时自己也在成长。同时也反省自己,以后要代码多加验证,谨慎细致,认真负责。

    问题: 
    1.getFields() 获取到 protected 类型字段的值

    这个原因至今没有再次重现,很奇怪,很费解

    2.getFields() 和 getDeclaredFields() 方法反射获取多了一个字段$change

    这个和开发工具的配置有关系,好像是因为开启了Instant run 造成的,而且Android Studio 2.2.3已经修复了,链接在这里

    参考资料

    Retrieving the inherited attribute names/values using Java Reflection

  • 相关阅读:
    容斥原理
    泰勒展开
    初等微积分
    粒子群优化(微粒群算法)
    生成函数
    FFT例题
    图论例题
    线段求交
    期望小小结
    [Violet]天使玩偶/SJY摆棋子
  • 原文地址:https://www.cnblogs.com/hfultrastrong/p/9283203.html
Copyright © 2011-2022 走看看