
本文将介绍如何在 Java 17 中使用反射来修改 final 字段的值。在 Java 12 及更高版本中,直接通过反射修改 Field 对象的 modifiers 字段的方式已经失效。本文提供了一种适用于 Java 17 的解决方案,该方案利用 VarHandle 和 JVM 启动参数来克服 Java 的模块化限制。
Java 17 引入了更强的模块化和封装性,直接修改 Field 对象的 modifiers 字段不再可行。一种替代方案是使用 VarHandle。VarHandle 提供了一种更安全、更灵活的方式来访问和操作类的字段,包括私有字段。
以下代码展示了如何使用 VarHandle 修改 final 字段:
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
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);
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.set(foo, "new value"); // 修改 final 字段的值
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(foo.getBar());
}
}代码解释:
立即学习“Java免费学习笔记(深入)”;
为了使上述代码正常工作,需要在启动 JVM 时添加以下参数:
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED
这些参数允许代码访问 java.base 模块中的 java.lang.reflect 和 java.net 包,这是使用 VarHandle 所必需的。 如果不添加这些参数,将会抛出java.lang.IllegalAccessException异常。
如何添加 JVM 启动参数:
虽然在 Java 17 中修改 final 字段变得更加困难,但通过使用 VarHandle 和适当的 JVM 启动参数,仍然可以实现这一目标。然而,请务必谨慎使用此技术,并充分了解其潜在风险。建议在确实需要绕过 final 限制的情况下才使用此方法,并仔细测试代码以确保其正确性和稳定性。
以上就是Java 17 中使用反射修改 final 字段的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号