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

本文主要是介绍getDeclaredFields()-Reflection反射-获取包括父类在内的所有字段,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

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

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

分析

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

写个小方法验证一下下~

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

 
  1. /**

  2. * 用作父类

  3. */

  4. public class ParentModel {

  5.  
  6. private String p_privateField;

  7. public String p_publicField;

  8. protected String p_protectedField;

  9. }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
 
  1. /**

  2. * 子类,继承上面定义的用作父类的ParentModel

  3. */

  4. public class Model extends ParentModel{

  5.  
  6. private String privateField;

  7. public String publicField;

  8. protected String protectedField;

  9.  
  10. }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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

 
  1. Field[] fs = Model.class.getFields();

  2. Field[] fs1 = Model.class.getDeclaredFields();

  3. for (Field f:fs) {

  4. Log.d("getFields","getFields---"+f.getName());

  5. }

  6.  
  7. for (Field f:fs1) {

  8. Log.d("getDeclaredFields","getDeclaredFields---"+f.getName());

  9. }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

这里写图片描述

getDeclaredFields()的打印输出:

这里写图片描述

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

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

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

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

 
  1. List<Field> fieldList = new ArrayList<>() ;

  2. Class tempClass = Model.class;

  3. while (tempClass != null) {//当父类为null的时候说明到达了最上层的父类(Object类).

  4. fieldList.addAll(Arrays.asList(tempClass .getDeclaredFields()));

  5. tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己

  6. }

  7. for (Field f : fieldList) {

  8.  
  9. Log.d("getAllFields","getFields---"+f.getName());

  10. }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这里写图片描述

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

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

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

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

  2. {

  3. ....

  4. }

  • 1
  • 2
  • 3
  • 4

更新说明

2017.6.27更新:

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

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

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

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

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

如果方法是 private修饰的,当你用反射去访问的时候setAccessible(true); 之后 才能访问

参考资料

Retrieving the inherited attribute names/values using Java Reflection

这篇关于getDeclaredFields()-Reflection反射-获取包括父类在内的所有字段的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/710210

相关文章

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

JS和jQuery获取节点的兄弟,父级,子级元素

原文转自http://blog.csdn.net/duanshuyong/article/details/7562423 先说一下JS的获取方法,其要比JQUERY的方法麻烦很多,后面以JQUERY的方法作对比。 JS的方法会比JQUERY麻烦很多,主要则是因为FF浏览器,FF浏览器会把你的换行也当最DOM元素。 <div id="test"><div></div><div></div

【反射知识点详解】

Java中的反射(Reflection)是一个非常强大的机制,它允许程序在运行时检查或修改类的行为。这种能力主要通过java.lang.reflect包中的类和接口来实现。 通过反射,Java程序可以动态地创建对象、调用方法、访问字段,以及获取类的各种信息(如构造器、方法、字段等)。 反射的用途 反射主要用于以下几种情况: 动态创建对象:通过类的Class对象动态地创建其实例。访问类的字段

vcpkg子包路径批量获取

获取vcpkg 子包的路径,并拼接为set(CMAKE_PREFIX_PATH “拼接路径” ) import osdef find_directories_with_subdirs(root_dir):# 构建根目录下的 "packages" 文件夹路径root_packages_dir = os.path.join(root_dir, "packages")# 如果 "packages"

Go 在orm中使用反射

作为静态语言,golang 稍显笨拙,还好 go 的标准包reflect(反射)包弥补了这点不足,它提供了一系列强大的 API,能够根据执行过程中对象的类型来改变程序控制流。本文将通过设计并实现一个简易的 mysql orm 来学习它,要求读者了解mysql基本知识,并且跟我一样至少已经接触 golang 两到三个月。 orm 这个概念相信同学们都非常熟悉,尤其是写过rails的同学,对acti

Weex入门教程之4,获取当前全局环境变量和配置信息(屏幕高度、宽度等)

$getConfig() 获取当前全局环境变量和配置信息。 Returns: config (object): 配置对象;bundleUrl (string): bundle 的 url;debug (boolean): 是否是调试模式;env (object): 环境对象; weexVersion (string): Weex sdk 版本;appName (string): 应用名字;

Collection的所有的方法演示

import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;public class TestCollection {/*** @param args* Collection的所有的方法演示* 此程序没有使用泛型,所以可以添加任意类型* 以后如果写到泛型会补充这一方面的内容*/public s

Temu官方宣导务必将所有的点位材料进行检测-RSL资质检测

关于饰品类产品合规问题宣导: 产品法规RSL要求 RSL测试是根据REACH法规及附录17的要求进行测试。REACH法规是欧洲一项重要的法规,其中包含许多对化学物质进行限制的规定和高度关注物质。 为了确保珠宝首饰的安全性,欧盟REACH法规规定,珠宝首饰上架各大电商平台前必须进行RSLReport(欧盟禁限用化学物质检测报告)资质认证,以确保产品不含对人体有害的化学物质。 RSL-铅,

类型信息:反射-Class

在说反射前提一个概念:RTTI(在运行时,识别一个对象的类型) public class Shapes {public static void main(String[] args) {List<Shape> shapes = Arrays.asList(new Circle(), new Square(), new Triangle());for (Shape shape : shapes

MFC中App,Doc,MainFrame,View各指针的互相获取

纸上得来终觉浅,为了熟悉获取方法,我建了个SDI。 首先说明这四个类的执行顺序是App->Doc->Main->View 另外添加CDialog类获得各个指针的方法。 多文档的获取有点小区别,有时间也总结一下。 //  App void CSDIApp::OnApp() {      //  App      //  Doc     CDocument *pD