当前位置 博文首页 > 文章内容

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

    作者:shunshunshun18 栏目:未分类 时间:2021-01-17 14:44:09

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    前言

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