利用java的反射,在运行时将需要修改的常量强制更改成我们所需要的值

——这样就不用修改jxl库了,只要在我们项目中加几句就OK了,出问题的概率也会小很多。

于是就研究了一下,虽然最后还是发现在这个方法在我们的项目不可行,不过还是很有收获的。

首先,利用反射修改私有静态常量的方法

对如下Bean类,其中的INT_VALUE是私有静态常量

classBean{

privatestaticfinalInteger INT_VALUE =100;

}

修改常量的核心代码:

System.out.println(Bean.INT_VALUE);

//获取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

说明用反射私有静态常量成功了。

方案的局限

注意到上述代码的中的静态常量类型是Integer——但是我们项目中实际需要修改的字段类型并不是包装类型Integer,而是java的基本类型int。

当把常量的类型改成int之后,

classBean{

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

这大概是JAVA反射的一个局限吧——修改基本类型的常量时,不是太可靠。

附一下我测试时候的DEMO吧

代码

importjava.lang.reflect.Field;

importjava.lang.reflect.Modifier;

importjava.util.Date;

publicclassForClass {

staticvoidsetFinalStatic(Field field, Object newValue)throwsException {

field.setAccessible(true);

Field modifiersField = Field.class.getDeclaredField("modifiers");

modifiersField.setAccessible(true);

modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

field.set(null, newValue);

}

publicstaticvoidmain(String args[])throwsException {

System.out.println(Bean.INT_VALUE);

setFinalStatic(Bean.class.getField("INT_VALUE"),200);

System.out.println(Bean.INT_VALUE);

System.out.println("------------------");

System.out.println(Bean.STRING_VALUE);

setFinalStatic(Bean.class.getField("STRING_VALUE"),"String_2");

System.out.println(Bean.STRING_VALUE);

System.out.println("------------------");

System.out.println(Bean.BOOLEAN_VALUE);

setFinalStatic(Bean.class.getField("BOOLEAN_VALUE"),true);

System.out.println(Bean.BOOLEAN_VALUE);

System.out.println("------------------");

System.out.println(Bean.OBJECT_VALUE);

setFinalStatic(Bean.class.getField("OBJECT_VALUE"),newDate());

System.out.println(Bean.OBJECT_VALUE);

}

}

classBean {

publicstaticfinalintINT_VALUE =100;

publicstaticfinalBoolean BOOLEAN_VALUE =false;

publicstaticfinalString STRING_VALUE ="String_1";

publicstaticfinalObject OBJECT_VALUE ="234";

}

代码输出

100

100

------------------

String_1

String_1

------------------

false

true

------------------

234

Fri Apr 25 00:55:05 CST 2014

说明

——其中的Boolean跟Object类型常量被正确修改了,而基本类型int和String的修改则“没有生效”。

java 反射 static final_Java_反射_修改final static问题相关推荐

  1. Java编程基础08——面向对象_构造方法静态static

    1.构造方法Constructor概述和格式(掌握) A:构造方法概述和作用 给对象的数据(属性)进行初始化 B:构造方法格式特点 a:方法名与类名相同(大小写也要与类名一致) b:没有返回值类型,连 ...

  2. [转载] JAVA 堆栈 堆 方法区 静态区 final static 内存分配 详解

    参考链接: 在Java中为静态最终static final变量分配值 转载来源:https://blog.csdn.net/peterwin1987/article/details/7571808 J ...

  3. java long 对应mybati类型_修改 mybatis-generator 中数据库类型和 Java 类型的映射关系...

    使用 mybatis-generator 发现数据库类型是 tinyint(4) , 生成 model 时字段类型是 Byte ,使用的时候有点不便 数据库的类型和 Model 中 Java 类型的关 ...

  4. java邮箱设置密送_修改后可以发送附件、抄送、密送的javabean,吐血推荐~(javamail范例)...

    修改后可以发送附件.抄送.密送的javabean,吐血推荐~(javamail范例) 作者:Andy.m    文章来源:www.jspcn.net 发布日期:2004年02月16日 /* *Auth ...

  5. java文件 默认打开方式_修改文件的默认打开方式(亲测有效)

    今天遇到了一个问题,那就是没办法修改文件的默认打开方式,Windos10系统. 可能我稍微有点强迫症什么的,每次默认记事本打开,虽然也可也选择其他的应用打开,但就是没有直接双击打开的爽. 一百度才发现 ...

  6. java tomcat打印日志级别_修改tomcatlog输出等级

    /usr/local/tomcat2/webapps/digital/WEB-INF/classes/log4j.properties log4j.properties配置如下(配置是转载): log ...

  7. java useragent 360 遨游 火狐_修改浏览器的User-Agent来伪装你的浏览器和操作系统

    修改浏览器的User-Agent来伪装你的浏览器和操作系统 浏览器 互联网 2010-05-13 阅读(99561) 近期很多文章都提到了User-Agent (UA) 字符串,但大部分网友都不知道这 ...

  8. 我的世界java版hud怎么设置_修改配置文件以关闭HUD和怪物隐身

    原先的配置文件注释全部去掉了 毕竟是机翻的 没什么参考价值 配置文件的内容非常多,找不到的话就搜索 感谢评论提醒,配置文件在 config\dynamicstealth 里,是一个单独的cfg文件 g ...

  9. JVM—堆栈 堆 方法区 静态区 final static 内存分配

    原文作者:一夜丶鱼龙舞 原文地址:JAVA 堆栈 堆 方法区 静态区 final static 内存分配 详解(转) 一.栈(stack)和堆(heap) (1)内存分配的策略 按照编译原理的观点,程 ...

最新文章

  1. protoc支持c_protoc 命令参数
  2. sentinel限流_微服务架构进阶:Sentinel实现服务限流、熔断与降级
  3. 面临找工作,要记住给自己的这些话。
  4. mysql left join 空值_MYSQL Left Join如何选择NULL值?
  5. 【转】推荐计算机科学类的经典书籍 3
  6. 三阶魔方花样玩法,公式汇总
  7. 成功解决D8016“/ZI”和“/Gy-”命令行选项不兼容
  8. 【CyberSecurityLearning 45】PHP基础+变量、运算符、流程控制语句
  9. docker镜像了解(建立私有仓库,基于已有镜像创建,Docker的数据管理) 基于Dockerfile创建,基于本地模板创建,端口映射,容器互联)
  10. AI:初学者如何从零学习人工智能?看完你就懂了
  11. 摘抄自知乎的redis相关
  12. 查看进程中占cpu高的线程方法
  13. Laravel 使用 scout 集成 elasticsearch 做全文搜索
  14. java颠倒字符串_Java经典实例:按字符颠倒字符串
  15. AZURE-百万像素定焦镜头
  16. 对于(不是特别不合理)的指摘、的对应方式(学会调整,不要一根筋)
  17. python 基础语法梳理
  18. lamp php的ssl,ssh支持
  19. 小米小爱蓝牙音箱_至今为止功能最全面的「小爱同学」!小米小爱音箱Pro体验...
  20. 不显示BOM清单的版本

热门文章

  1. 推荐 :谷歌微软等科技巨头数据科学岗位面试题(108道)
  2. 教你用Camtasia简单几步制作精美片头
  3. QGroundControl(QGC)飞控地面站二次开发-修改地图
  4. 赵阳日记--- 成为外贸高手该具备哪些知识
  5. 2021年全球路标漆收入大约3022百万美元,预计2028年达到4112百万美元
  6. To_10_r_100_8_1---判断出三盏灯分别是由哪个开关控制的
  7. stm32点亮三个led灯
  8. linux企业微信清理存储空间,微信系列——关闭微信企业号应用
  9. 2020-09-05 CCM宽间隔跳频序列背景研究
  10. 如何同步两台Linux机器的时间?