gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:06:00 25 4
gpt4 key购买 nike

在 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 对象,但它没有任何看起来有用的方法。在调试器中,我注意到 overrideFieldAccessor 设置在第一个示例中返回的第二个 Field 上,并且没有看到对修饰符的更改。不过,我不确定该怎么做。

如果有影响,我正在使用 openjdk-8

最佳答案

如果你想让修饰符 hack(不要忘记 it is a total hack)起作用,你需要在你第一次访问字段。

因此,在执行 f.getInt(null); 之前,您需要执行以下操作:

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

原因是,无论有多少不同的实际java.lang.reflect.Field,为类的每个字段(*)只创建一个内部FieldAccessor对象> 你拥有的元素。当它在 UnsafeFieldAccessorFactory 中构造 FieldAccessor 实现时,对 final 修饰符的检查就完成了一次。 .

当确定您无法访问 final static 字段时(因为 setAccessible 覆盖不起作用,但非静态 final 字段,但不适用于 static final fields),即使通过不同的 Field 对象,它也会在每次后续反射中不断失败,因为它一直使用相同的 FieldAccessor

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

// NOTE that there is no synchronization used here. It is correct (though not efficient) to generate more than one FieldAccessor for a given Field.

关于在先前的反射之后设置静态最终字段的 Java 反射失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48198108/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com