我最近偶然发现Change private static final field using Java reflection并测试了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);
}
}
打印
Everything is false
有人知道为什么吗? setFinalStatic实际上是否有效?
答案 0 :(得分:18)
通过使值成为方法调用的结果,即使是虚拟调用,也可以避免编译器内联。
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);
}
}
打印
Everything is false
Everything is true
答案 1 :(得分:13)
当访问原始静态最终字段时,Java编译器将假定该值是常量并内联该值而不是生成访问该字段的代码。这意味着编译器将替换为FALSE
字段的引用,其值为false
。如果使用反射来访问该字段,您将看到该字段的值实际已更改。
这对非原始字段不起作用,因为在编译时无法内联对象引用的值。