Poison

AccessibleObject.isAccessible()

关于反射时经常使用的 AccessibleObject.isAccessible() 方法,我一直以为是被 public 修饰就返回 true,其他的就返回 false,今天调试代码时发现对 ArrayList 的无参构造函数调用 isAccessible() 返回的竟然是 false,于是查阅了相关代码,在 java.lang.reflect.AccessibleObject 类中有以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Get the value of the {@code accessible} flag for this object.
*
* @return the value of the object's {@code accessible} flag
*/
public boolean isAccessible() {
return override;
}

// Indicates whether language-level access checks are overridden
// by this object. Initializes to "false". This field is used by
// Field, Method, and Constructor.
//
// NOTE: for security purposes, this field must not be visible
// outside this package.
boolean override;

根据源码可知,isAccessible() 返回的为字段 override 的值,注释表示该字段表明是否语言级别的检查被覆盖,默认为 false,并不是我之前认为的修饰符是否为 public 的含义,个人认为这个方法名具有迷惑性,因为在 Oracle 的官方文档 Controlling Access to Members of a Class 中,将修饰符称为 Access level modifiers,容易让人误解 AccessibleObject.isAccessible() 的含义。在 AccessibleObject 的文档描述中,有以下说明:

By default, a reflected object is not accessible.

比如以下测试代码,输出结果为 false:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package me.tianshuang;

import java.lang.reflect.Constructor;
import java.util.ArrayList;

public class AccessibleTest {

public static void main(String[] args) throws NoSuchMethodException {
Class<?> clazz = ArrayList.class;
Constructor<?> constructor = clazz.getDeclaredConstructor();
System.out.println(constructor.isAccessible());
}

}

但是,在 java.lang.reflect.Proxy#newProxyInstance 的方法实现中有以下代码:

1
2
3
4
5
6
7
8
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}

在调用 setAccessible(true) 之前进行了方法修饰符的检查,这是为什么呢?

Reference

Why a public constructor is not accessible via reflection - Stack Overflow