有时候我们在当前类需要获取操作另一个类声明为private的成员变量值时,我们需要用到setAccessible()方法。
关于setAccessible():
- Method、Field和Constructor对象都有setAccessible()方法。
- setAccessible作用是启动和禁用访问安全检查的开关。
- setAccessible()方法需要一个布尔值的参数。
- 参数值为true则指示反射的对象在使用时抑制Java语言访问检查。
- 参数值为false则指示反射的对象执行Java语言访问检查。
利用setAccessible操作私有成员变量
package Reflection;
import java.lang.reflect.Field;
public class TestFunction {
public static void main(String[] args) throws ClassNotFoundException,
IllegalAccessException, InstantiationException, NoSuchFieldException {
Class clazz = Class.forName("Reflection.Tclass");
Tclass t = (Tclass) clazz.newInstance();
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(t, "test");
System.out.println(t.getName());
}
}
class Tclass {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
未设置setAccessible(true)时操作私有成员变量会报错
Exception in thread "main" java.lang.IllegalAccessException: Class Reflection.TestFunction can not access a member of class Reflection.Tclass 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.set(Field.java:761)
at Reflection.TestFunction.main(TestFunction.java:12)Process finished with exit code 1
所以setAccessible()方法使得原本无法访问的私有成员也可以访问。
提高反射代码的执行效率
setAccessible()方法还可以提高反射的代码执行效率。如果代码中必须用反射,同时该句代码需要频繁的被调用,那么可以设置setAccessible(true)。
package Reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestFunction {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
test01();
test02();
test03();
}
public static void test01() {
Tclass tclass = new Tclass();
long bl = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
tclass.testMethod();
}
long el = System.currentTimeMillis();
System.out.println("普通方法执行时间 " + (el - bl) + "ms");
}
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Tclass tclass = new Tclass();
Class aClass = tclass.getClass();
Method testMethod = aClass.getMethod("testMethod");
long bl = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
testMethod.invoke(tclass);
}
long el = System.currentTimeMillis();
System.out.println("反射方法执行时间 " + (el - bl) + "ms");
}
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Tclass tclass = new Tclass();
Class aClass = tclass.getClass();
Method testMethod = aClass.getMethod("testMethod");
testMethod.setAccessible(true);
long bl = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
testMethod.invoke(tclass);
}
long el = System.currentTimeMillis();
System.out.println("免检方法执行时间 " + (el - bl) + "ms");
}
}
class Tclass {
public void testMethod() {
int a = 0;
}
}
结果:
普通方法执行时间 8ms
反射方法执行时间 4539ms
免检方法执行时间 1999ms