Java反射—Field類使用

Field作為反射中對應(yīng)類或?qū)ο笾械挠蚧蛘呓凶鰧傩缘牟僮黝悾宋仪耙黄恼轮械牡玫矫趾皖愋偷润镎拢現(xiàn)ield的作用不限于此烙荷。

*上篇文章:Java反射-初探反射基礎(chǔ))(點(diǎn)擊進(jìn)入) *

Java SE 8的Docs這樣說:A Field provides information about, and dynamic access to, a single field of a class or an interface. The reflected field may be a class (static) field or an instance field.

簡單理解就是:我們可用通過Field類對類或?qū)ο蟮膄ield進(jìn)行動態(tài)操作。

  • 關(guān)于Field的一些方法:
返回值 名字和參數(shù) 作用
Object get(Object obj) 返回這個object對應(yīng)field字段的Object
xxx getXXX(Object obj) 同上檬寂,不過XXX可以是Int,Char,Boolean等
void set(Object obj, Object value) 設(shè)置obj對象的調(diào)用方法的這個field的值為value
void setXXX(Object obj, XXX value) 設(shè)置特定類型值,例setInt(Object obj,int value)
Class getDeclaringClass() 返回定義中的Class對象
String getName() 得到名字的字符串
int getModifier() 返回一個修飾符的值
Class getType() 返回這個field的對象Class
void setAccessible(boolean flag) 設(shè)置是否允許set get
boolean isAccessible() 查看field是否允許set和get终抽。
... ... ...

其他的可以去Java的官方文檔去查看。https://docs.oracle.com/javase/8/docs/api/

  • 簡單案例:

    package io.ilss.reflection;
    
    /**
     * className User
     * description User
     *
     * @author feng
     * @version 1.0
     * @date 2019-01-26 19:11
     */
    public class User {
        private String username;
        private String password;
        private int sex;
        public String address; //注意這個是public
    
        public User() {
        }
    
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
        
        ...//getter setter method
    }
    
    package io.ilss.reflection;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Field;
    
    /**
     * className UserTest
     * description UserTest
     *
     * @author feng
     * @version 1.0
     * @date 2019-01-26 19:12
     */
    public class UserTest {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
            User user = new User("ilss", "ilss password");
            Class cls = user.getClass();
            //獲取username名字的Field
            Field usernameField = cls.getDeclaredField("username");
            System.out.println(usernameField.toString());
    
            //獲取user對象對應(yīng)的username
            Object o = getSafe(usernameField, user);
            System.out.println("The username value of user is " + o);
    
            //獲取基本數(shù)據(jù)類型
            user.setSex(1);
            Field sexField = cls.getDeclaredField("sex");
            sexField.setAccessible(true);
            sexField.setInt(user, 2);
            int sex = sexField.getInt(user);
            System.out.println("user sex : " + sex);
    
            //對user進(jìn)行修改值 pubic不需要setAccessible
            Field addressField = cls.getDeclaredField("address");
            addressField.set(user, "ilss address");
            System.out.println("user address : " + user.getAddress());
    
    
        }
    
        public static Object getSafe(Field field, Object obj) {
            Object ret = null;
            try {
                if (field.isAccessible()) {
                    ret = field.get(obj);
    
                } else {
                    field.setAccessible(true);
                    ret = field.get(obj);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return ret;
        }
    }
    
    

    需要說的點(diǎn):

    • setAccessible方法。是Field繼承自AccessibleObject類昼伴,AccessibleObject是Field匾旭、Method、Constuctor類的父類圃郊。簡單理解意思就是 如果類型是private修飾的价涝,你不可以直接訪問,就需要設(shè)置訪問權(quán)限為true.如果是public則不需要設(shè)置持舆。
    • set和get調(diào)用的時候都需要確鄙瘢可以訪問,不然如果不能訪問拋出IllegalAccessException逸寓。
  • 制作一個通用的toString(Object obj)方法

package io.ilss.reflection;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;

/**
 * className ObjectAnalyzer
 * description ObjectAnalyzer
 *
 * @author feng
 * @version 1.0
 * @date 2019-01-26 19:34
 */
public class ObjectAnalyzer {
    private ArrayList<Object> visited = new ArrayList<>();
    
    public String toString(Object obj) {
        //無效處理
        if (obj == null) {
            return "null";
        }
        //注意 如果不判斷contains可能會出現(xiàn)無限遞歸調(diào)用居兆。
        if (visited.contains(obj)) {
            return "...";
        }
        //將已經(jīng)處理的做記錄
        visited.add(obj);
        Class cls = obj.getClass();
        //如果為String類型就直接返回
        if (cls == String.class) {
            return (String) obj;
        }

        //是否數(shù)組
        if (cls.isArray()) {
            //用StringBuilder來append字符串
            StringBuilder r = new StringBuilder(cls.getComponentType() + "[]{");
            //利用relect包的Array操作類來便利
            for (int i = 0; i < Array.getLength(obj); i++) {
                if (i > 0) {
                    r.append(",");
                }
                Object val = Array.get(obj, i);
                // getComponentType() 得到數(shù)組對象元素的類型
                // isPrimitive()是判斷是否是基本數(shù)據(jù)類型
                if (cls.getComponentType().isPrimitive()) {
                    r.append(val);
                } else {
                    //不是基本數(shù)據(jù)類型就遞歸調(diào)用。
                    r.append(toString(val));
                }
            }
            return r + "}";
        }


        StringBuilder ret = new StringBuilder(cls.getName());
        do {
            ret.append("[");

            Field[] fields = cls.getDeclaredFields();
            //對fields數(shù)組的所有訪問權(quán)限設(shè)置為true
            AccessibleObject.setAccessible(fields, true);

            for (Field f : fields) {
                //只對非static參數(shù)處理
                if (!Modifier.isStatic(f.getModifiers())) {
                    //如果不是第一個就加逗號
                    if (!ret.toString().endsWith("[")) {
                        ret.append(",");
                    }
                    ret.append(f.getName()).append("=");
                    try {
                        //對field的值進(jìn)行獲取
                        Class t = f.getType();
                        Object val = f.get(obj);
                        //基本數(shù)據(jù)類型就直接append 不是就遞歸調(diào)用
                        if (t.isPrimitive()) {
                            ret.append(val);
                        } else {
                            ret.append(toString(val));
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            ret.append("]");
            //處理父類
            cls = cls.getSuperclass();
        }
        while (cls != null);

        return ret.toString();
    }
    
    @Override
    public String toString() {
        //利用自己調(diào)用toString(this)來實(shí)現(xiàn)自己的toString
        return this.toString(this);
    }
}

注意:

里面有個Array類席覆,是java.lang.reflect包下一個數(shù)組操作類史辙。代碼里的調(diào)用意思都不難理解。就不解釋了

  • 調(diào)用類
package io.ilss.reflection;

import java.util.ArrayList;
import java.util.List;

/**
 * className ObjectAnalyzerTest
 * description ObjectAnalyzerTest
 *
 * @author feng
 * @version 1.0
 * @date 2019-01-26 19:30
 */
public class ObjectAnalyzerTest {
    public static void main(String[] args) {
        List<Integer> squares = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            squares.add(i * i);
        }
        System.out.println(new ObjectAnalyzer().toString(squares));

        System.out.println(new ObjectAnalyzer().toString());

        User[] arr = new User[10];
        System.out.println(new ObjectAnalyzer().toString(arr));

        User user = new User("ilss", "ilss password");
        System.out.println(new ObjectAnalyzer().toString(user));
    }
}

相關(guān)代碼的github:https://github.com/imyiren/java-base-ilss

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末佩伤,一起剝皮案震驚了整個濱河市聊倔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌生巡,老刑警劉巖耙蔑,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異孤荣,居然都是意外死亡甸陌,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門盐股,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钱豁,“玉大人,你說我怎么就攤上這事疯汁∩撸” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵幌蚊,是天一觀的道長谤碳。 經(jīng)常有香客問我,道長溢豆,這世上最難降的妖魔是什么蜒简? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮漩仙,結(jié)果婚禮上搓茬,老公的妹妹穿的比我還像新娘犹赖。我一直安慰自己,他們只是感情好卷仑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布冷尉。 她就那樣靜靜地躺著,像睡著了一般系枪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上磕谅,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天私爷,我揣著相機(jī)與錄音,去河邊找鬼膊夹。 笑死衬浑,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的放刨。 我是一名探鬼主播工秩,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼进统!你這毒婦竟也來了助币?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤螟碎,失蹤者是張志新(化名)和其女友劉穎眉菱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掉分,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡俭缓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了酥郭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片华坦。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖不从,靈堂內(nèi)的尸體忽然破棺而出惜姐,到底是詐尸還是另有隱情,我是刑警寧澤消返,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布载弄,位于F島的核電站,受9級特大地震影響撵颊,放射性物質(zhì)發(fā)生泄漏宇攻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一倡勇、第九天 我趴在偏房一處隱蔽的房頂上張望逞刷。 院中可真熱鬧嘉涌,春花似錦、人聲如沸夸浅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帆喇。三九已至甩苛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間追葡,已是汗流浹背益咬。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留婉刀,地道東北人吟温。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像突颊,于是被迫代替她去往敵國和親鲁豪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容