JAVA 利用反射修改修飾符為static+final的成員變量的值


問題:今天項目有一個需求,需要new一個HashMap,將它賦值給一個修飾符為static+final的Map。

思路:不能停服,那就只能動態修改了,那必然用到反射。反射的一些基礎知識請自行學習

參考:1、http://my.oschina.net/dxqr/blog/215504?p={{totalPage}} 

     2、http://stackoverflow.com/questions/3301635/change-private-static-final-field-using-java-reflection

代碼:

 1 /**
 2  * 修改靜態final字段的值
 3  * @author chenzl
 4  * 2015-09-22
 5  */
 6 public class SetFinalValue {
 7 
 8     public static final Map<Integer, Integer> openMap = new HashMap<Integer, Integer>(); 9 10 public static void main(String[] args) throws Exception { 11 Field target = SetFinalValue.class.getField("openMap"); 12 13 int modify = target.getModifiers(); 14  SetFinalValue.checkModifier(modify); 15 16 Map<Integer, Object> openMap2 = new HashMap<Integer, Object>(); 17 openMap2.put(2, "abcde"); 18 try { 19 //取消 Java 語言訪問檢查,詳細查看 API(這里可以不寫) 20 target.setAccessible(true); 21 22 //獲得修飾符Field對象,通過這個對象可以對另外一個Field對象的操作符進行修改,源碼見圖-1 23 Field modifiersField = Field.class.getDeclaredField("modifiers"); 24 modifiersField.setAccessible(true); 25 26 //關於Modefier常量的定義見圖-2 27 modify = target.getModifiers() & ~Modifier.FINAL; 28 System.out.println("處理后的 modify : " + modify); 29 30 //更改目標對象的修飾符 31  modifiersField.setInt(target, modify); 32 modify = target.getModifiers(); 33 34 System.out.println("#####更改修飾符后的結果######"); 35  SetFinalValue.checkModifier(modify); 36 37 //更改靜態常量 38 target.set(null, openMap2); 39 40 System.out.println(openMap.get(2)); 41 } catch (Exception e) { 42  e.printStackTrace(); 43  } 44 45 /**重復設置一次*/ 46 Map<Integer, Object> openMap3 = new HashMap<Integer, Object>(); 47 openMap3.put(3, "中文輸入"); 48 try { 49 target = SetFinalValue.class.getField("openMap"); 50 target.setAccessible(true); 51 System.out.println("#####重復一次檢驗一次重新get后值會不會改變######"); 52  checkModifier(target.getModifiers()); 53 54 } catch (Exception e) { 55  e.printStackTrace(); 56  } 57 58  } 59 60 /** 61 * 檢查所有的修飾符,是否是 public static final 62 * @param modify 63 */ 64 public static void checkModifier(int modify){ 65 System.out.println("當前的 modify : " + modify); 66 //源碼見圖-3 67 System.out.println(" public : " + Modifier.isPublic(modify)); 68 System.out.println(" static : " + Modifier.isStatic(modify)); 69 System.out.println(" final : " + Modifier.isFinal(modify)); 70  } 71 }

 

程序結果:

總結:先拿到成員變量的Field對象,從Field對象中獲得所有修飾符,修改它的修飾符,然后設置對象的值。

 

 

圖-1:

 

圖-2:

 圖-3:

 

 

其他:

1、測試基本數據類型 int

 

2、測試Integer類型:

 

3、String類型

3.1 String類型的其他方式

 

關於String類型出現的特殊情況,我暫時也不知道原因,猜測是與String類型的常量池有關,有待我以后去證實。

3.2 當我用一個新的常量去替換時成功了。

那么我暫時理解成 open變量指向常量池的一個內存地址,在編譯器就確定了,不能動態指向常量池外的內存地址,只能重新指向常量池內的另外一個內存地址。

 


 

2017-7-29  修改:

jdk版本:1.8.0.31

文章的最后出現一個錯誤,3.2中的open是一個新new的對象,不管是直接傳入“開始”還是傳入str都可以修改它。如果open是通過對象池創建的,則不會改變。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM