1. 程式人生 > >Field類的setAccessible()方法

Field類的setAccessible()方法

      或許標題上說的並不是很準確,setAccessible方法準確得說是從AccessibleObject類繼承過來的,不過這麼說也沒什麼錯,就不要糾結這個了,讓我們進入主題

  public class User {
private String name;
public User(String name) {
this.name = name;
}


public String getName() {
return name;
}


public void setName(String name) {
this.name = name;
}



}

測試:

import java.lang.reflect.Field;


public class Demo {
public static void main(String[] args) throws Exception {  
   Class clazz = User.class;
       User u = new User("小明");
       for (Field f : clazz.getDeclaredFields()) {  
           System.out.println(f.isAccessible());//這裡的結果是false
           f.setAccessible(true);
           System.out.println(f.getName()+":"+f.get(u));
       }  
 
   }  


}

通過執行以上程式碼,我們發現  System.out.println(f.isAccessible())這一句列印結果是"false",從字面上理解是說該欄位不能被訪問,但是為了保險起見我們還是去看一下原始碼(Java有的時候就是比較坑,不一定能夠見名知意,我們還是保險點比較好,雖然不算是做學問,但是學習的態度還是一絲不苟比較好),首先我們去掉f.setAccessible(true);

然後在 System.out.println(f.getName()+":"+f.get(u));這行打斷點,但是發現不了問題,經過檢查發現getName()這個方法並不拋異常,也就是是就算沒有加f.setAccessible(true);

也可以獲得name,拋異常的是f.get(u);這句話,我找到Field中的get(Object obj)方法,發現有這麼一句

if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers);
            }
        }

這裡的override就是我們用setAccessible設定的值,但是接下來就坑爹了Reflection以及其他幾個類的原始碼不在jdk自帶的原始碼中,找了半天才找到sun的原始碼,匯入原始碼(最好將sun的原始碼和java的放在一個資料夾裡,不然一次只能匯入一個原始碼,要來回切換,比較麻煩)

然後我們debug定位到了Reflection類的ensureMemberAccess方法如圖:


圖中有一個verifyMemberAccess方法,這就是丟擲異常的方法,進入該方法直接到了 boolean successSoFar = false;然後就return false了,因此丟擲了IllegalAccessException異常,也就是說我們得出結論當isAccessible()的結果是false時不允許通過反射訪問該欄位

結論:當isAccessible()的結果是false時不允許通過反射訪問該欄位

當該欄位時private修飾時isAccessible()得到的值是false,必須要改成true才可以訪問

所以     f.setAccessible(true);得作用就是讓我們在用反射時訪問私有變數