Java 反射 調用私有域和方法(setAccessible)
@author ixenos
AccessibleObject類
Method、Field和Constructor類共同繼承了AccessibleObject類,該基類有兩個setAccessible方法能在運行時壓制Java語言訪問控制檢查(Java language access control checks),從而能任意調用被私有化保護的方法、域和構造方法
public class AccessibleObjectextends Objectimplements AnnotatedElementAccessibleObject 類是 Field、Method 和 Constructor 對象的基類。它提供了將反射的對象標記為在使用時取消默認 Java 語言訪問控制檢查的能力。對於公共成員、默認(打包)訪問成員、受保護成員和私有成員,在分別使用 Field、Method 或 Constructor 對象來設置或獲取字段、調用方法,或者創建和初始化類的新實例的時候,會執行訪問檢查。
在反射對象中設置 accessible 標志允許具有足夠特權的復雜應用程序(比如 Java Object Serialization 或其他持久性機制)以某種通常禁止使用的方式來操作對象。
兩個setAccessible方法設置訪問權限
static void |
setAccessible(AccessibleObject[] array, boolean flag) 使用單一安全性檢查(為了提高效率)為一組對象設置 accessible 標志的便捷方法。 |
void |
setAccessible(boolean flag) 將此對象的 accessible 標志設置為指示的布爾值。 |
setAccessible
public static void setAccessible(AccessibleObject[] array, boolean flag) throws SecurityException
- 使用單一安全性檢查(為了提高效率)為一組對象設置 accessible 標志的便捷方法。
首先,如果存在安全管理器,則在
ReflectPermission("suppressAccessChecks")權限下調用checkPermission方法。如果
flag為true,但是不能更改輸入array的任何元素的可訪問性(例如,如果元素對象是Class類的Constructor對象),則會引發SecurityException。如果發生 SecurityException,對於少於(不包括)發生異常的元素的數組元素,可以將對象的可訪問性設置為flag;對於超出(包括)引發異常的元素的那些元素,則不更改其可訪問性。
- 參數:
array- AccessibleObjects 的數組flag- 每個對象中的 accessible 標志的新值- 拋出:
SecurityException- 如果請求被拒絕。- 另請參見:
SecurityManager.checkPermission(java.security.Permission),RuntimePermission
setAccessible
public void setAccessible(boolean flag) throws SecurityException
- 將此對象的 accessible 標志設置為指示的布爾值。值為 true 則指示反射的對象在使用時應該取消 Java 語言訪問檢查。值為 false 則指示反射的對象應該實施 Java 語言訪問檢查。
首先,如果存在安全管理器,則在
ReflectPermission("suppressAccessChecks")權限下調用checkPermission方法。如果
flag為true,並且不能更改此對象的可訪問性(例如,如果此元素對象是Class類的Constructor對象),則會引發SecurityException。如果此對象是
java.lang.Class類的Constructor對象,並且flag為 true,則會引發SecurityException。
- 參數:
flag- accessible 標志的新值- 拋出:
SecurityException- 如果請求被拒絕。- 另請參見:
SecurityManager.checkPermission(java.security.Permission),RuntimePermission
示例
被測類:
1 class Employee{ 2 private int id; 3 private String name; 4 private int age; 5 6 public Employee(){ 7 8 } 9 public Employee(int id, String name, int age){ 10 this.id = id; 11 this.name = name; 12 this.age = age; 13 } 14 15 private void setId(int id){ 16 this.id = id; 17 } 18 private int judge(int id){ 19 return this.id - id; 20 } 21 private String sayHalo(String name){ 22 return "Halo" + name; 23 } 24 }
測試類:
1 public class PrivateTest{ 2 public static void main(String[] args){ 3 Employee em = new Employee(1, "Alex", 22); 4 //獲取Class對象 5 Class<?> emClass = em.getClass(); 6 7 //獲取特定的聲明了的方法 8 Method judgeMethod = emClass.getDeclaredMethod("judge", new Class[]{Integer.TYPE}); 9 //setAccessible(boolean flag)使所有成員可以訪問,訪問之前設置 10 judgeMethod.setAccessible(true); 11 12 //獲取所有聲明的方法 13 Method[] allMethods = emClass.getDeclaredMethods(); 14 //AccessibleObject.setAccessible(AccessibleObject[] array, 15 boolean flag)批量給訪問權限 16 AccessibleObject.setAccessible(allMethods, true); 17 18 //下面就可以通過反射訪問了 19 judgeMethod.invoke(em, new Object[]{3}); 20 21 //or... 22 for(Method method : allMethods){ 23 ... 24 } 25 } 26 }
