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

 

 

 

转载于:https://www.cnblogs.com/chenzl1024/p/4835319.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值