[01][01][04][01] setAccessible方法

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)的方式关闭安全检查就可以达到提升反射速度的效果

上一篇:Java> Java核心卷读书笔记 - 反射


下一篇:参数错误导致的依赖注入的错误提示:A suitable constructor for type 'MyApp.OptionMethodSetting' could not be