我正在尝试通过 Java 17 中的反射覆盖非静态最终字段的值。
据我所知,从 Java 12 及以上版本开始,你不能再执行以下技巧:
import java.lang.reflect.*;
class Foo {
private final String bar;
public Foo(String bar) {
this.bar = bar;
}
public String getBar() {
return this.bar;
}
}
public class Example {
public static void main(String[] args) {
Foo foo = new Foo("foobar");
System.out.println(foo.getBar());
try {
Field field = foo.getClass().getDeclaredField("bar");
field.setAccessible(true);
Field modifiers = field.getClass().getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(foo.getBar());
}
}
当我在 Java 17 中运行它时,抛出以下异常:
foobar java.lang.NoSuchFieldException: modifiers at java.base/java.lang.Class.getDeclaredField(Class.java:2610) at Example.main(Example.java:24) foobar
“bar”的值保持不变。
对于较新版本的 Java 是否有覆盖 Final 字段的等效方法?在谷歌中快速搜索并没有产生与上述解决方案不同的任何结果。我唯一了解到的是,不可能覆盖静态最终字段,而仍然可以通过反射覆盖非静态最终字段,但我不知道如何实现。
也许已经晚了,但我找到了解决方案这里。 Java17修饰符
您需要添加 JVM 启动选项:
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED
--add-opens=java.base/java.net=ALL-UNNAMED
Java代码:
VarHandle MODIFIERS;
var lookup = MethodHandles.privateLookupIn(Field.class, MethodHandles.lookup());
MODIFIERS = lookup.findVarHandle(Field.class, "modifiers", int.class);
MODIFIERS.set(field, field.getModifiers() & ~Modifier.FINAL);
这应该有效:
Field field = foo.getClass().getDeclaredField("bar");
field.setAccessible(true);
field.set(foo, "changedBar");