内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用
有一个带有private static final
字段的类,不幸的是,我需要在运行时更改。
使用反射我得到这个错误: java.lang.IllegalAccessException: Can not set static final boolean field
有没有办法改变价值?
Field hack = WarpTransform2D.class.getDeclaredField("USE_HACK");
hack.setAccessible(true);
hack.set(null, true);
假设没有SecurityManager
阻止你这样做,你可以使用setAccessible
绕过private
并重置修饰符来摆脱final
,并实际修改一个private static 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"
。
这里实际做的是如下:
boolean
值true
和false
in main
被自动装箱以引用类型Boolean
“常量” Boolean.TRUE
和Boolean.FALSE
public static final Boolean.FALSE
引用所Boolean
引用的Boolean.TRUE
false
被自动装箱时Boolean.FALSE
,它指的是与Boolean
所提到的相同Boolean.TRUE
"false"
现在的一切都是"true"
static final File.separatorChar
单元测试Integer
缓存,变异String
等的例子每当你做这样的事情时,都应该格外小心。它可能不起作用,因为SecurityManager
可能存在,但即使它不存在,取决于使用模式,它可能或可能不起作用。
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.FINAL
从field.getModifiers()
。&
是按位和,并且~
是按位补码。
仍然无法解决这个问题?,就像我为此所做的那样陷入了萧条?你的代码看起来像这样吗?
public class A {
private final String myVar = "Some Value";
}
阅读这个答案的评论,特别是@Pshemo的评论,它提醒我,Constant Expression的处理方式不同,因此无法对其进行修改。因此,您需要将代码更改为如下所示:
public class A {
private final String myVar;
private A() {
myVar = "Some Value";
}
}
从Java语言规范第17章第17.5.4节“写保护字段”中获得一点好奇心:
通常,可能不会修改最终和静态字段。但是,System.in,System.out和System.err是静态最终字段,由于遗留原因,必须允许通过方法System.setIn,System.setOut和System.setErr更改这些字段。我们将这些字段称为写保护,以区别于普通的最终字段。
资料来源:http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.4