問題:今天項目有一個需求,需要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是通過對象池創建的,則不會改變。

