1. 背景
在测试枚举类型实现单例模式能抵抗反射机制破解的代码中,看constructor.setAccessible(true)代码,不明白其用途
2. setAccessible方法详解
setAccessible并不是在Field中的,而是在AccessibleObject中,AccessibleObject类是Field(字段),Method(方法),Constructor(构造器)类的基类,它提供反射对象绕过Java语言权限控制检查的权限
public static void setAccessible(AccessibleObject[] array, boolean flag)
throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
for (int i = 0; i < array.length; i++) {
setAccessible0(array[i], flag);
}
}
public void setAccessible(boolean flag) throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
setAccessible0(this, flag);
}
private static void setAccessible0(AccessibleObject obj, boolean flag)
throws SecurityException
{
if (obj instanceof Constructor && flag == true) {
Constructor<?> c = (Constructor<?>)obj;
if (c.getDeclaringClass() == Class.class) {
throw new SecurityException("Cannot make a java.lang.Class" +
" constructor accessible");
}
}
obj.override = flag;
}
setAccessible(AccessibleObject[] array, boolean flag)
第一个参数array ,就是要设置flag标志位的Field/Method/Constructor对象的数组,第二个参数flag,将array数组的所有Field/Method/Constructor对象设置为flag标识符的新值
3. setAccessible方法使用
在测试了中方别对私有构造方法,私有方法,私有字段设置不检验权限
-
访问权限类
@Data @AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private Double score;
private String testMethod(){
return "abcd";
}
} -
测试类
public class SetAccessibleTest { public static void main(String[] args) {
try {
Class<?> clazz = User.class;
Constructor constructor = clazz.getDeclaredConstructor(null);
// 私有构造方法设置不检查权限
constructor.setAccessible(true);
User user = (User) constructor.newInstance();
// 所有私有属性的方法设置不检查权限
Method[] methods = clazz.getDeclaredMethods();
AccessibleObject.setAccessible(methods, true);
// 所有私有属性的字段设置不检查权限
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
fields[0].setLong(user,1L);
} catch (Exception e) {
e.printStackTrace();
}
}
}
由于JDK的安全检查耗时较多,所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的效果