天天看點

Java反射學習總結二(用反射調用對象的私有屬性和方法)

大家都知道正常的調用是不可以通路對象的private修飾的屬性和方法的,這也是Java的封裝性原則。

但是有沒有方法可以強制去通路對象的private修飾的屬性和方法呢?那就是用反射!(這個可能在面試題中被問到哦)

接下來就來看看是如何實作的:

我們先去jdk裡看一下描述屬性的類Field,和方法的類Method:

java.lang.reflect

java.lang.Object

java.lang.reflect.AccessibleObject

java.lang.reflect.Field

java.lang.reflect.Method

可以看到這兩個類有個共通的特點,就是他們都繼承自java.lang.reflect.AccessibleObject這個類,我們好好看看這個類的描述

<dl></dl>

<dt></dt>

All Implemented Interfaces:

<dd>AnnotatedElement</dd>

Direct Known Subclasses:

<dd></dd>

Constructor, Field, Method

The AccessibleObject class is the base class for Field, Method and Constructor objects. It provides the ability to flag a reflected object as suppressing default Java language access control checks when it is used. The access checks--for public, default (package) access, protected, and private members--are performed when Fields, Methods or Constructors are used to set or get fields, to invoke methods, or to create and initialize new instances of classes, respectively.

大緻意思就是:

這個AccessibleObject類是Field, Method and Constructor對象的一個父類,他可以讓一個反射對象去禁止Java語言的通路控制檢測。控制檢測有public, default (package) access, protected, and private。。。blah blah blah。。。

這裡我貼出控制通路控制檢測的這個方法:(這個類裡還有一些相關的方法,有興趣的大家可以自己去看看)

Set the <code>accessible</code> flag for this object to the indicated boolean value. A value of <code>true</code> indicates that the reflected object should suppress Java language access checking when it is used. A value of <code>false</code>indicates that the reflected object should enforce Java language access checks.

大緻意思:

設定标志去訓示對象的boolean值,如果是true則禁止java通路控制檢查,如果是false則強制反射對象使用java通路控制檢查

知道了這個方法就可以做一個小例子測試一下啦。

下面這個例子很簡單,就是定義一個dog類,裡面有個private的屬性dogName,和private的方法say。

main函數裡用反射先去修改dogName,然後在調用say方法列印出來:

[java] view plain copy print?

public class Test2 {  

    public static void main(String[] args) throws Exception {  

        //獲得Dog類的Class對象  

        Class&lt;?&gt; classType = Class.forName("Dog");  

        //生成對象的執行個體  

        Object obj = classType.newInstance();  

        //取得dogName屬性  

        Field dogName = classType.getDeclaredField("dogName");  

        //禁止Field的通路控制檢查  

        dogName.setAccessible(true);  

        //将Field的值設為“Xiao Qiang”  

        dogName.set(obj, "Xiao Qiang");  

        //取得say()方法  

        Method say = classType.getDeclaredMethod("say", new Class[]{});  

        //禁止say方法的通路控制檢查  

        say.setAccessible(true);  

        //調用say方法  

        say.invoke(obj, new Object[]{});  

    }  

}  

 class Dog {  

    //私有的屬性  

    private String dogName = "Wang Cai";  

    //私有的方法  

    private void say() {  

        System.out.println(dogName + ": Wang Wang");  

輸出結果:Xiao Qiang: Wang Wang

這裡需要特别注意一個地方:

如果想用反射修改通路控制檢查的話,擷取Method和Field對象的時候一定要用getDeclaredField和getDeclaredMethod。不要用getField和getMethod。

雖然這兩個方法的參數都是相同的,但不同點在于getMethod和getField隻能獲得public修飾的屬性和方法。而getDeclared可以擷取任何類型的屬性和方法,因為這個例子要調用私有的屬性和方法,是以要用getDeclaredXX。