程序地带

Java 反射修改类的常量值、静态变量值、属性值


前言

有的时候,我们需要修改一个变量的值,但变量也许存在于 Jar 包中或其他位置,导致我们不能从代码层面进行修改,于是我们就用到了下面的场景,通过反射来进行修改变量的值。


定义一个实体类
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之后。


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

在其他代码都不变的情况下,代码输出的结果竟然变成了诡异的:


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 = 100


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的优化代码提高运行效率的一个行为,但是就会导致我们在用反射改变此常量值时出现类似不生效的错觉。


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/jichi/p/14287621.html

随机推荐

Windows系统常见API

CoreAudioMMDeviceAPI(mmdeviceapi.h)IMMDeviceEnumerator枚举音频设备集(IMMDeviceCollectionÿ...

师从小白 阅读(985)

学习笔记-Kafka消息队列

学习笔记-Kafka消息队列

官网地址:https://kafka.apache.org/一、认识kafka1、认识kafkaApacheKafka是Apache软件基金会的开源的流处理平台,该平台提供了消息的订阅与...

天天代码码天天 阅读(213)

Pandas数据结构

Pandas数据结构一、Series(序列)简介Series是一维数组,表格中的每一行或者每一列结构都可以看成是Series,又行索引和数值构成...

Martin ! 阅读(599)

python实现详细日期数据存储到mysql

问题背景1、脚本用于定时接收数据和时间2、将收到的数据和系统的时间存储到mysql数据库中3、希望存储成为us的数据,具体格式如下4、对于mysql来说其字段的配置如下:遇...

没有水杯和雨伞的工科男 阅读(705)

windows快捷键

Ctrl+C:复制Ctrl+V:粘贴Ctrl+A:全选Ctrl+X:剪切Ctrl+Z:撤销...

ea简单sy 阅读(927)