反射機制中獲取private成員的值

首先,我們要了解三個反射包中的類:
Constructor:代表類的單個構造方法,通過Constructor我們可執行一個類的某個構造方法(有參或者無參)來創建對象時。

       Method:代表類中的單個方法,可以用於執行類的某個普通方法,有參或無參,並可以接收返回值。

       Field:代表類中的單個屬性,用於set或get屬性

       AccessibleObject:以上三個類的父類,提供了構造方法,普通方法,和屬性的訪問控制的能力。

使用Class類中的方法可以獲得該類中的所有Constructor對象,Method對象,和Field對象。但是任然無法訪問私有化的構造方法,普通方法,和私有屬性,此時我們可以使用他們繼承父類(AccessibleObject)中的setAccessible()方法,來設置或取消訪問檢查,以達到訪問私有對象的目的。

我們來看下例子:

@Data
public class Demo {

    public String name;
    private String title;

}
public class Test {

    public static void main(String[] args) {
        try {
            Class clazz = Class.forName("com.lian.demo.Demo");
            Demo demo = (Demo) clazz.newInstance();
            demo.setName("name1");
            demo.setTitle("title1");

            Field[] fields = clazz.getDeclaredFields();
            Arrays.stream(fields).forEach(field -> {
                try {
                    System.out.println("成員變量"+field.getName()+"的值爲:"+field.get(demo));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

}

執行結果如下

成員變量name的值爲:name1
java.lang.IllegalAccessException: Class com.lian.demo.Test can not access a member of class com.lian.demo.TestDemo with modifiers "private"
	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
	at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
	at java.lang.reflect.Field.get(Field.java:390)
	at com.lian.demo.Test.lambda$main$0(Test.java:38)
	at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
	at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
	at com.lian.demo.Test.main(Test.java:31)

說明反射機制中無法獲取到private成員的值。那到底有沒有辦法獲取到?當然是有。Java反射機制提供的setAccessible()方法可以取消Java的權限控制檢查。

Arrays.stream(fields).forEach(field -> {
                boolean flag = field.isAccessible();
                System.out.println(field.getName() + ":" + flag);
                try {
                    //設置該屬性總是可訪問
                    field.setAccessible(true);
                    System.out.println("成員變量"+field.getName()+"的值爲:"+field.get(demo));
                } catch (IllegalAccessException e) {
                    System.out.println(e.getMessage());
                }
                //還原可訪問權限
                field.setAccessible(flag);
            });

這下沒問題了,可以獲取到了。setAccessible(true)取消了Java的權限控制檢查,但不是改變方法或字段的訪問權限。而對於setAccessible()方法是否會破壞類的訪問規則,產生安全隱患,我在知乎上面看到的一篇回答貌似很有道理:

Alt

發佈了65 篇原創文章 · 獲贊 33 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章