2016-12-17 33 views
1

我从Change private static final field using Java reflection了参考和下面的代码写了更新的字符串类型的静态最终字段的值:提起值更新与Java反射

我有一个类,它包含一个常量象下面这样:

public final class Constants { 

    public static final String ACCEPTED = "A"; 
} 

我尝试更新它的值使用Java反射,象下面这样:

Field field = Constants.class.getDeclaredField("ACCEPTED"); 
    field.setAccessible(true); 

    Field modifiersField = Field.class.getDeclaredField("modifiers"); 
    modifiersField.setAccessible(true); 
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); 

    String newValue = "B"; 
    field.set(null, newValue); 

通过使用上述代码更新值之后我测试了它象下面这样:

String myUpdatedValue = Constants.ACCEPTED; 

在这里,当我检查Constants.ACCEPTED值正被显示为“B”,但是当我检查myUpdatedValue,它被示出作为“A”。无法理解原因。即使当我将此值作为参数传递给某个其他方法时,在方法调用时它是“B”,但在被调用的方法中它是“A”

回答

1

引述the documentation

注:如果原始类型或字符串被定义为一个常数,该值在编译时已知,编译器无处不在的代码替换常量名它的价值。这被称为编译时常量。如果外部世界的常量值发生变化(例如,如果规定pi实际应该是3.975),则需要重新编译任何使用此常量的类来获取当前值。

在你的情况下,Constants.ACCEPTED就是这样一个编译时间常量。因此,当编译代码时,所有对Constants.ACCEPTED的引用实际上都替换为字面值"A"。你的代码在运行时处理它的值,但这已经太晚了。

+0

非常感谢您的上述解释,完全合理,所以在运行时解决此问题的任何方式?除了创建方法并从该方法返回String。 – proudandhonour

+1

@proudandhonour我想你可以使用某种形式的字节码操作,如[javassist](https://jboss-javassist.github.io/javassist/),但在运行和实现它之前,我会非常仔细地考虑这一点。这很麻烦,而且通常很脆弱,所以你需要100%确定你真的想要这样做。 – Mureinik