Java 反射修改類的常量值、靜態變量值、屬性值

前言

有的時候,咱們須要修改一個變量的值,但變量也許存在於 Jar 包中或其餘位置,致使咱們不能從代碼層面進行修改,因而咱們就用到了下面的場景,經過反射來進行修改變量的值。java

定義一個實體類

class Bean{  
    private static final Integer INT_VALUE = 100;  
}

利用反射修改私有靜態常量方法

System.out.println(Bean.INT_VALUE);  
Field field = Bean.class.getField("INT_VALUE");  
//將字段的訪問權限設爲true:即去除private修飾符的影響  
field.setAccessible(true);  
//去除final修飾符的影響,將字段設爲可修改的 
Field modifiersField = Field.class.getDeclaredField("modifiers");  
modifiersField.setAccessible(true);  
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);  
//把字段值設爲200  
field.set(null, 200);  
System.out.println(Bean.INT_VALUE);

修改私有靜態常量測試結果

100
200

看到測試結果說明咱們的反射修改爲功了。測試

利用反射修改共有靜態變量方法

class Bean{  
    public static int nums = 100;
}
 

System.out.println(Bean.nums);
Field field = Bean.class.getField("nums");
field.set(null, 200);
System.out.println(Bean.INT_VALUE);優化

 

測試結果修改爲功。調試

100
200

奇怪的地方

注意到上述代碼的中的靜態常量類型是Integer,可是咱們項目中實際須要修改的字段類型並非包裝類型Integer,而是java的基本類型int。
當把常量的類型改爲int以後。code

class Bean{  
    private static final int INT_VALUE = 100;//把類型由Integer改爲了int  
}

在其餘代碼都不變的狀況下,代碼輸出的結果居然變成了詭異的:orm

100
100

並且在調試的過程當中發現,在第二次輸出的時候,內存中的Bean.INT_VALUE是已經變成了200,可是System.out.println(Bean.INT_VALUE)輸出的結果卻依然時詭異的100?!
是反射失效了嗎?
又試了其餘幾種類型,發現這種貌似失效的情會發生在int、long、boolean以及String這些基本類型上,而若是把類型改爲Integer、Long、Boolean這種包裝類型,或者其餘諸如Date、Object都不會出現失效的狀況。內存

奇怪的緣由

對於基本類型的靜態常量,JAVA在編譯的時候就會把代碼中對此常量中引用的地方替換成相應常量值。
參考:Modifying final fields in Java
即對於常量 public static final int maxFormatRecordsIndex = 100get

if( index > maxFormatRecordsIndex   ){  
    index  =  maxFormatRecordsIndex ;  
}

這段代碼在編譯的時候已經被java自動優化成這樣的:
if( index > 100){
index = 100;
}
因此在INT_VALUE是int類型的時候。編譯

System.out.println(Bean.INT_VALUE);

編譯時會被優化成下面這樣:
System.out.println(100);
因此,天然,不管怎麼修改Boolean.INT_VALUE,System.out.println(Bean.INT_VALUE)都仍是會依然執拗地輸出100了。
這自己是JVM的優化代碼提升運行效率的一個行爲,可是就會致使咱們在用反射改變此常量值時出現相似不生效的錯覺。class

相關文章
相關標籤/搜索