1. 程式人生 > >getDeclaredFields()-Reflection反射-獲取包括父類在內的所有欄位

getDeclaredFields()-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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
/**
 * 子類,繼承上面定義的用作父類的ParentModel
 */
public class Model extends ParentModel{

    private String privateField;
    public String publicField;
    protected
String protectedField; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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()); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

見證答案的時候到了~ 
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());
}
  • 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迴圈再新增一個條件:

while (tmpClass !=null && !tmpClass.getName().toLowerCase().equals("java.lang.object") )
{
      ....
}
  • 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已經修復了,連結在這裡

參考資料

相關推薦

getDeclaredFields()-Reflection反射-獲取包括在內的所有

前言今天Android移動端要加個新功能,所以迴歸Android程式設計師的身份.開發的過程中,發現了之前的程式碼寫的有很多問題,真的應該把時間抽出來重構一下了.其中有反射的一個坑,工具類某方法反射獲取傳入Model的屬性值.但是當我把公共屬性抽出來做基類的時候,發現獲取不到

Java反射程式碼 得到某所有 getFields()與getDeclaredFields()區別 getMethod()和getDeclaredMethod()區別

** * 得到某類的所有欄位 * */ public void reflect2(){       try {           Class cls = Class.forName("entity.UserBean");//載入UserBean類到記憶體中!獲取一個Cla

java中使用反射獲取pojo(實體)所有

 說起反射,不得不說它實在是太強大了,通過反射就可以輕輕鬆鬆拿到各種東東,如果你想在專案中解除對某個類的依賴,可以考慮用反射。        今天跟大家分享的是通過java中的反射,獲取pojo類的所有欄位值。 &nb

部類的繼承從而實現對的private的引用

子類 public class SubClass extends SuperClass.InnerClass { SuperClass superClass; public SubClass (SuperClass superClass){ superClass.

java反射獲取聚合<List>屬性

java反射獲取聚合<List>屬性欄位 2016年09月30日 11:59:40 閱讀數:7997 標籤: javareflect 更多 個人分類: java 需要動態的傳入一個Class的型別,然後反射到啟動的List,根

引用的靜態,不會導致子初始化

先看程式碼 // 父類 public class SuperClass { static { System.out.println("SuperClass Init!"); } public static int valu

group_concat ——sql語句在group後,組所有獲取

經常寫sql的都知道,group處理的sql,一般是為了獲取一些統計引數,或者分組的欄位等等,如果分組後,想要獲取某個組內的所有欄位,這時就需要使用 此函式返回字串結果,其中NULL包含來自組的連線非值。NULL如果沒有非NULL值,則返回 。完整語法如下: GR

Yii2獲取指定表中的所有

參考地址: https://blog.csdn.net/xinren369/article/details/51865424 public function actionTableField(){ $tableName= 'member'; (表名)

反射獲取所有屬性包括

/** * 獲取所有屬性包括父類 * @param object * @return */ public static Field[] getAllFields(Object object){ Class clazz = object.getClass();

java 反射獲取泛型對象的所有字段與對應的值(包括的)

date lse 代碼 out lda ble alt http info 上代碼: public static void main(String[] args) throws IntrospectionException { SysUser obj =

180530-反射獲取泛型的實際參數

sys party params 情況下 imp upload sbo 如果 type() 文章鏈接:https://liuyueyi.github.io/hexblog/2018/05/30/180530-通過反射獲取泛型類的實際參數/ 反射獲取泛型類的實際參數 泛型用得

java反射機制——獲取位元組碼對應中的

package cn.itcast.reflect.demo; import java.lang.reflect.Field; public class ReflectDemo3 { public static void main(String[] args) throws ClassNot

【java】如何通過反射獲取泛型

核心程式碼:(編寫在父類中) public class BaseDaoImpl<T> implements BaseDao<T> {     private Class<

java反射——獲取一個Object物件的一切!

有些時候你明明知道這個object裡面是什麼,但是因為種種原因,你不能將它轉化成一個物件,只是想單純地提取出這個object裡的一些東西,這個時候就需要用反射了。 假如你這個類是這樣的: private class User { String userName;

java反射獲取泛型

public class Person<T> { } import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; public class Student ext

(繼承方式)反射獲取泛型的型別和物件

1.工具類,用於獲取泛型類的型別和物件public abstract class FatherReflectUtils<T> { public T getTInstance() th

Java反射:通過物件呼叫子方法

通常情況下在父類中不能直接呼叫子類中的方法(重寫的除外),但是在某些特殊的情況下,需要根據一個父類的物件來呼叫子類的方法,原理就使用java的反射原理。例如:Person類,有一個name屬性publ

Eclipse4.7使用基礎 在創建的時候,進行設置自動實現抽象所有抽象方法

sleep 所有 png 2-2 finish highlight lips ner eclipse os :windows7 x64 jdk:jdk-8u131-windows-x64 ide:Eclipse Oxygen Release (4.7.0

java利用反射獲取某個包下的所有獲取物件屬性、方法、並例項化

首先貼上用到的jar包,當然也可以通過遞迴file.list獲取類的路徑名稱。 maven匯入jar包: <dependency> <groupId>

java反射機制 以及通過反射獲得的變數,方法,建構函式

        Class clz =Class.forName("day_29_ReflectAndJson.Person");         //前面獲取本類及其父類共有的方法就不再寫了 直接獲得本類中的所有方法 並傳引數後呼叫本方法         Method[] method=clz.getDec