我正在使用一些注释来动态设置类中的字段值.因为无论是public,protected还是private,我想这样做,setAccessible(true)每次调用set()方法之前,我都调用Field对象.我的问题是这个setAccessible()电话会对电影本身产生什么样的影响?
更具体地说,它是一个私有字段和这组代码调用setAccessible(true).如果代码中的其他位置然后通过反射检索相同的字段,那么该字段是否已经可访问?或者getDeclaredFields(),getDeclaredField()方法每次都返回Field对象的新实例吗?
我想另一种陈述问题的方法是,如果我打电话setAccessible(true),在我完成之后将它设置回原始值有多重要?
Mor*_*sen 79
随着setAccessible()你改变的行为AccessibleObject,即Field实例,而不是类的实际领域.这是文档(摘录):
值
true表示反射对象在使用时应禁止检查Java语言访问控制
一个可运行的例子:
public class FieldAccessible {
public static class MyClass {
private String theField;
}
public static void main(String[] args) throws Exception {
MyClass myClass = new MyClass();
Field field1 = myClass.getClass().getDeclaredField("theField");
field1.setAccessible(true);
System.out.println(field1.get(myClass)); // no exception
Field field2 = myClass.getClass().getDeclaredField("theField");
System.out.println(field2.get(myClass)); // IllegalAccessException
}
}
Run Code Online (Sandbox Code Playgroud)
正如其他发帖者所指出的,setAccessible仅适用于您的该实例java.lang.reflect.Field,因此不需要将可访问性设置回其原始状态。
然而...
如果您希望调用field.setAccessible(true)持久,您需要使用java.lang.Class和中的底层方法java.lang.reflect.Field。面向公众的方法会向您发送实例的副本Field,因此每次您执行类似操作后它都会“忘记”class.getField(name)
import java.lang.reflect.*;
import sun.reflect.FieldAccessor;
public class Reflect {
private static Method privateGetDeclaredFields;
private static Method getFieldAccessor;
public static Field[] fields(Class<?> clazz) throws Exception {
return (Field[]) privateGetDeclaredFields.invoke(clazz, false);
}
public static <T> T get(Object instance, Field field) throws Exception {
return ((FieldAccessor) getFieldAccessor.invoke(field, instance)).get(instance);
}
public static void set(Object instance, Field field, Object value) throws Exception {
((FieldAccessor) getFieldAccessor.invoke(field, instance)).set(instance, value);
}
static {
try {
// These are used to access the direct Field instances instead of the copies you normally get through #getDeclaredFields.
privateGetDeclaredFields = Class.class.getDeclaredMethod("privateGetDeclaredFields", boolean.class);
privateGetDeclaredFields.setAccessible(true);
getFieldAccessor = Field.class.getDeclaredMethod("getFieldAccessor", Object.class);
getFieldAccessor.setAccessible(true);
} catch (Exception e) {
// Should only occur if the internals change.
e.printStackTrace();
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新:此实现适用于 Java 8,未来版本更改了后端,从而打破了这一点。如果您确实希望继续此策略,则相同的概念仍然适用。