Java 反射 调用私有域和方法(setAccessible)
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 }