或许标题上说的并不是很准确,setAccessible方法准确得说是从AccessibleObject类继承过来的,不过这么说也没什么错,就不要纠结这个了,让我们进入主题
setAccessible方法是干什么用的呢让我们来看一段代码吧
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试:
import java.lang.reflect.Field;
public class Demo {
public static void main(String[] args) throws Exception {
Class clazz = User.class;
User u = new User("小明");
for (Field f : clazz.getDeclaredFields()) {
System.out.println(f.isAccessible());//这里的结果是false
f.setAccessible(true);
System.out.println(f.getName()+":"+f.get(u));
}
}
}
通过运行以上代码,我们发现 System.out.println(f.isAccessible())这一句打印结果是"false",从字面上理解是说该字段不能被访问,但是为了保险起见我们还是去看一下源代码(Java有的时候就是比较坑,不一定能够见名知意,我们还是保险点比较好,虽然不算是做学问,但是学习的态度还是一丝不苟比较好),首先我们去掉f.setAccessible(true);
然后在 System.out.println(f.getName()+":"+f.get(u));这行打断点,但是发现不了问题,经过检查发现getName()这个方法并不抛异常,也就是是就算没有加f.setAccessible(true);
也可以获得name,抛异常的是f.get(u);这句话,我找到Field中的get(Object obj)方法,发现有这么一句
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
checkAccess(Reflection.getCallerClass(), clazz, obj, modifiers);
}
}
这里的override就是我们用setAccessible设置的值,但是接下来就坑爹了Reflection以及其他几个类的源码不在jdk自带的源码中,找了半天才找到sun的源代码,导入源代码(最好将sun的源代码和java的放在一个文件夹里,不然一次只能导入一个源代码,要来回切换,比较麻烦)
然后我们debug定位到了Reflection类的ensureMemberAccess方法如图:
图中有一个verifyMemberAccess方法,这就是抛出异常的方法,进入该方法直接到了 boolean successSoFar = false;然后就return false了,因此抛出了IllegalAccessException异常,也就是说我们得出结论当isAccessible()的结果是false时不允许通过反射访问该字段
结论:当isAccessible()的结果是false时不允许通过反射访问该字段
当该字段时private修饰时isAccessible()得到的值是false,必须要改成true才可以访问
所以 f.setAccessible(true);得作用就是让我们在用反射时访问私有变量