我有一个类private static final,不幸的是,我需要在运行时更改它。
private static final
使用反射我得到这个错误:java.lang.IllegalAccessException: Can not set static final boolean field
java.lang.IllegalAccessException: Can not set static final boolean field
有没有办法改变价值?
Field hack = WarpTransform2D.class.getDeclaredField("USE_HACK"); hack.setAccessible(true); hack.set(null, true);
假设 noSecurityManager阻止您这样做,您可以使用setAccessible绕过private并重置修饰符以摆脱final,并实际修改private static final字段。
SecurityManager
setAccessible
private
final
这是一个例子:
import java.lang.reflect.*; public class EverythingIsTrue { static void setFinalStatic(Field field, Object newValue) throws Exception { field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } public static void main(String args[]) throws Exception { setFinalStatic(Boolean.class.getField("FALSE"), true); System.out.format("Everything is %s", false); // "Everything is true" } }
假设没有SecurityException抛出,上面的代码打印"Everything is true".
SecurityException
"Everything is true"
这里实际做了如下:
boolean
true
false
main
Boolean
Boolean.TRUE
Boolean.FALSE
public static final Boolean.FALSE
"false"
"true"
每当您执行此类操作时,都应格外小心。它可能不起作用,因为 aSecurityManager可能存在,但即使它不存在,取决于使用模式,它可能会或可能不会起作用。
JLS 17.5.3 最终字段的后续修改 在某些情况下,例如反序列化,系统将需要final在构造后更改对象的字段。final可以通过反射和其他依赖于实现的方式更改字段。唯一具有合理语义的模式是构造一个对象,然后final更新对象的字段。final在对象字段的所有更新完成之前,不应使对象对其他线程可见,也不应读取final字段。字段的冻结final发生在设置字段的构造函数的末尾,以及通过反射或其他特殊机制final对字段进行的每次修改之后。final 即便如此,仍有许多并发症。如果final在字段声明中将字段初始化为编译时常量,则final可能不会观察到该字段的更改,因为该final字段的使用在编译时被编译时常量替换。 另一个问题是规范允许积极优化final字段。在线程中,允许final使用未在构造函数中发生的对最终字段的修改对字段的读取进行重新排序。
JLS 17.5.3 最终字段的后续修改
在某些情况下,例如反序列化,系统将需要final在构造后更改对象的字段。final可以通过反射和其他依赖于实现的方式更改字段。唯一具有合理语义的模式是构造一个对象,然后final更新对象的字段。final在对象字段的所有更新完成之前,不应使对象对其他线程可见,也不应读取final字段。字段的冻结final发生在设置字段的构造函数的末尾,以及通过反射或其他特殊机制final对字段进行的每次修改之后。final
即便如此,仍有许多并发症。如果final在字段声明中将字段初始化为编译时常量,则final可能不会观察到该字段的更改,因为该final字段的使用在编译时被编译时常量替换。
另一个问题是规范允许积极优化final字段。在线程中,允许final使用未在构造函数中发生的对最终字段的修改对字段的读取进行重新排序。
private static final boolean
本质上,
field.getModifiers() & ~Modifier.FINAL
关闭对应于Modifier.FINALfrom的位field.getModifiers()。&是按位与,并且~是按位补码。
Modifier.FINAL
field.getModifiers()
&
~
仍然无法解决这个问题?像我一样陷入抑郁症吗?你的代码看起来像这样吗?
public class A { private final String myVar = "Some Value"; }
阅读对此答案的评论,特别是@Pshemo 的评论,它提醒我常量表达式的处理方式不同,因此 无法 修改它。因此,您需要将代码更改为如下所示:
public class A { private final String myVar; private A() { myVar = "Some Value"; } }