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是通过对象池创建的,则不会改变。

 

 

 

posted @ 2015-09-24 14:48  chenzl1024  阅读(4164)  评论(2编辑  收藏  举报