Bootstrap

field.setAccessible(true)

Accessable属性是继承自AccessibleObject 类. 功能是启用或禁用安全检查
在反射对象中设置 accessible 标志允许具有足够特权的复杂应用程序(比如 Java Object Serialization 或其他持久性机制)以某种通常禁止使用的方式来操作对象。
setAccessible
public void setAccessible(boolean flag)
throws SecurityException

将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。

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时不允许通过反射访问该字段

实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问,一般情况下,我们并不能对类的私有字段进行操作,利用反射也不例外,但有的时候,例如要序列化的时候,我们又必须有能力去处理这些字段,这时候,我们就需要调用AccessibleObject上的setAccessible()方法来允许这种访问,而由于反射类中的Field,Method和Constructor继承自AccessibleObject,因此,通过在这些类上调用setAccessible()方法,我们可以实现对这些字段的操作。但有的时候这将会成为一个安全隐患,为此,我们可以启用java.security.manager来判断程序是否具有调用setAccessible()的权限。默认情况下,内核API和扩展目录的代码具有该权限,而类路径或通过URLClassLoader加载的应用程序不拥有此权限。例如:当我们以这种方式来执行上述程序时将会抛出异常

java.lang.IllegalAccessException: Class com.example.xj.myapplication.TestField can not access a member of class com.example.xj.myapplication.Student with modifiers "private"
	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
	at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
	at java.lang.reflect.Field.get(Field.java:390)
	at com.example.xj.myapplication.TestField.main(TestField.java:20)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

所以 f.setAccessible(true);得作用就是让我们在用反射时访问私有变量

;