无法使用 Java 反射更改静态最终字段?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14102000/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cannot change static final field using java reflection?
提问by Evgeniy Dorofeev
I recently stumbled upon Change private static final field using Java reflectionand tested polygenelubricants' EverythingIsTrue
class, works fine, System.out.format("Everything is %s", false);
prints Everything is true
indeed. But when I change the code as
我最近偶然发现了使用 Java 反射的 Change private static final 字段并测试了 polygenelubricants 的EverythingIsTrue
类,工作正常,确实System.out.format("Everything is %s", false);
打印Everything is true
。但是当我将代码更改为
public class EverythingIsTrue {
public static final boolean FALSE = false;
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(EverythingIsTrue.class.getField("FALSE"), true);
System.out.format("Everything is %s", FALSE);
}
}
it prints
它打印
Everything is false
Does anybody know why? Does setFinalStatic actually work or not?
有人知道为什么吗?setFinalStatic 真的有效吗?
回答by Peter Lawrey
You can avoid compiler inlining by making the value a result of a method call, even a dummy one.
您可以通过使值成为方法调用的结果(甚至是虚拟调用)来避免编译器内联。
public class Main {
// value is not known at compile time, so not inlined
public static final boolean FLAG = Boolean.parseBoolean("false");
static void setFinalStatic(Class clazz, String fieldName, Object newValue) throws NoSuchFieldException, IllegalAccessException {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
Field modifiers = field.getClass().getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
public static void main(String... args) throws Exception {
System.out.printf("Everything is %s%n", FLAG);
setFinalStatic(Main.class, "FLAG", true);
System.out.printf("Everything is %s%n", FLAG);
}
}
prints
印刷
Everything is false
Everything is true
回答by Jan B
When accessing primitive static final fields, the Java compiler will assume that the value is a constant and inline the value instead of generating code that accesses the field. This means that the compiler will replace with the reference to the FALSE
field with the value false
. If you use reflection to access the field, you will see that the value of the field has actually changed.
当访问原始静态 final 字段时,Java 编译器将假定该值是一个常量并内联该值,而不是生成访问该字段的代码。这意味着编译器将替换为对FALSE
具有值的字段的引用false
。如果使用反射访问该字段,您会看到该字段的值实际上发生了变化。
This will not work for non-primitive fields, as the value of an object reference can not be inlined at compile time.
这不适用于非原始字段,因为在编译时无法内联对象引用的值。