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

1. 背景

在測試枚舉類型實現單例模式能抵抗反射機制破解的代碼中,看constructor.setAccessible(true)代碼,不明白其用途java

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方法使用

在測試了中方別對私有構造方法,私有方法,私有字段設置不檢驗權限ide

  • 訪問權限類測試

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
    private Long id;
    private String name;
    private Integer age;
    private Double score;
    private String testMethod(){
    return "abcd";
    }
    }
  • 測試類this

    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)的方式關閉安全檢查就能夠達到提高反射速度的效果code

相關文章
相關標籤/搜索