2016-12-17 29 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