为什么在更改字段修饰符之前我不能使用方法get(java.lang.reflect.Field#get) [英] why I can`t use method get(java.lang.reflect.Field#get) before changing field`s modifiers
问题描述
java代码如下。
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
C c = new C();
Field field = c.getClass().getDeclaredField("NAME");
field.setAccessible(true);
System.out.println(field.get(c));//Cause program exception on line 15 while using method get(java.lang.reflect.Field#get).
Field modifiers = field.getClass().getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
System.out.println(Modifier.toString(field.getModifiers()));
field.set(c,"James");
System.out.println(field.get(c));
}
}
class C{
private static final String NAME = "Clive";
public String toString(){
return NAME;
}
}
使用java时发生异常。 lang.reflect.Field #set.Exception信息如下。但是,如果我在第9行删除代码(System.out.println(field.get(c));),则不会发生异常
Exception in thread "main" java.lang.IllegalAccessException: Can not set static final java.lang.String field C.NAME to java.lang.String
at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:73)
at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:77)
at sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:77)
at java.lang.reflect.Field.set(Field.java:741)
at Test.main(Test.java:15)
推荐答案
字段
懒惰地创建一个名为的对象FieldAccessor
实际上负责获取
和设置
操作。这可以在 Field.get
(存档)。您可以单击方法 getFieldAccessor
以深入调用堆栈。这将(目前)最终将您带到一个方法 sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor
( archive )你可以看到修饰符被读取一次然后被烘焙到字段访问器的实际类型。
Field
lazily creates an object called a FieldAccessor
which is actually responsible for get
and set
operations. This can be seen in the source code for Field.get
(archive). You can click on the method getFieldAccessor
to go deeper in to the call stack. This will (at the moment) eventually take you to a method sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor
(archive) where you can see that the modifiers are read once and then baked in to the actual type of the field accessor.
在更改修饰符之前调用 Field.get
会影响输出,因为它导致在 final
被删除之前实例化字段访问器。
Calling Field.get
before changing the modifiers affects the output because it causes the field accessor to be instantiated before final
is removed.
你是可能会使用类似下面的代码来清除字段访问器:
You could possibly use something like the following bit of code to clear the field accessors:
public static void clearFieldAccessors(Field field)
throws ReflectiveOperationException {
Field fa = Field.class.getDeclaredField("fieldAccessor");
fa.setAccessible(true);
fa.set(field, null);
Field ofa = Field.class.getDeclaredField("overrideFieldAccessor");
ofa.setAccessible(true);
ofa.set(field, null);
Field rf = Field.class.getDeclaredField("root");
rf.setAccessible(true);
Field root = (Field) rf.get(field);
if (root != null) {
clearFieldAccessors(root);
}
}
使用它会导致问题中的代码通过,如果在 field.get(...)
和之间插入
。 clearFieldAccessors(field)
field.set(...)
Using that causes the code in the question to pass, if you insert clearFieldAccessors(field)
in between field.get(...)
and field.set(...)
.
当然,无法保证任何一项必须有效,并且可能 clearFieldAccessors
中的代码会导致一些我不知道的问题。
There is, of course, no guarantee that any of this has to work, and it's possible that the code in clearFieldAccessors
will cause some problem that I'm unaware of.
这篇关于为什么在更改字段修饰符之前我不能使用方法get(java.lang.reflect.Field#get)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!