繁体   English   中英

在前一次反射之后,设置静态最终字段的Java反射失败

[英]Java reflection to set static final field fails after previous reflection

在Java中,事实证明,字段访问器被缓存,并且使用访问器具有副作用。 例如:

class A {
    private static final int FOO = 5;
}

Field f = A.class.getDeclaredField("FOO");
f.setAccessible(true);
f.getInt(null); // succeeds

Field mf = Field.class.getDeclaredField("modifiers" );
mf.setAccessible(true);

f = A.class.getDeclaredField("FOO");
f.setAccessible(true);
mf.setInt(f, f.getModifiers() & ~Modifier.FINAL);
f.setInt(null, 6); // fails

class A {
    private static final int FOO = 5;
}

Field mf = Field.class.getDeclaredField("modifiers" );
mf.setAccessible(true);

f = A.class.getDeclaredField("FOO");
f.setAccessible(true);
mf.setInt(f, f.getModifiers() & ~Modifier.FINAL);
f.setInt(null, 6); // succeeds

这是失败的堆栈跟踪的相关位:

java.lang.IllegalAccessException: Can not set static final int field A.FOO to (int)6
    at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)
    at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:100)
    at sun.reflect.UnsafeQualifiedStaticIntegerFieldAccessorImpl.setInt(UnsafeQualifiedStaticIntegerFieldAccessorImpl.java:129)
    at java.lang.reflect.Field.setInt(Field.java:949)

这两个反射访问当然发生在我的代码库的非常不同的部分,我真的不想改变第一个来修复第二个。 有没有办法改变第二次反射访问以确保它在两种情况下都成功?

我试着看看Field对象,它没有任何看似他们会帮助的方法。 在调试器中,我注意到在第一个示例中返回的第二个Field上设置了overrideFieldAccessor ,但没有看到修改器的更改。 不过,我不知道该怎么办。

如果它openjdk-8 ,我正在使用openjdk-8

如果你想修饰符黑客(不要忘记它是完全黑客 ),你需要在第一次访问该字段之前更改modifiers私有字段。

所以,在你做f.getInt(null); ,你需要这样做:

mf.setInt(f, f.getModifiers() & ~Modifier.FINAL);

原因是,无论您有多少不同的实际java.lang.reflect.Field对象,都只为类(*)的每个字段创建一个内部FieldAccessor对象。 而对于检查final ,当它构建在该FieldAccessor执行修改器进行一次UnsafeFieldAccessorFactory

当确定你无法访问final static字段时(因为setAccessible覆盖不起作用,但非静态的最终字段,但不适用于static最终字段),它将为每次后续反射保持失败,即使是通过不同的Field对象,因为它一直使用相同的FieldAccessor

(*)禁止同步问题; 作为评论中Field提及的源代码:

//注意这里没有使用同步。 为给定的字段生成多个FieldAccessor是正确的(尽管效率不高)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM