Java中final的属性值怎么利用反射机制进行修改

发布时间:2020-12-02 17:31:07

来源:亿速云

阅读:96

作者:Leah

今天就跟大家聊聊有关Java中final的属性值怎么利用反射机制进行修改,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

假设有个类

class Person {

public final String name = "Mike";

}

这里声明 name 为非静态的属性只是为了说明反射修改 final 属性无关乎静态不静态,静态只是表现在它是一个类属性,在一个类加载器空间只会有一份拷贝,仅此而已。

创建一个通用方法进行反射修改属性值

public static void modify(Object object, String fieldName, Object newFieldValue) throws Exception {

Field field = object.getClass().getDeclaredField(fieldName);

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

modifiersField.setAccessible(true); //Field 的 modifiers 是私有的

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

if(!field.isAccessible()) {

field.setAccessible(true);

}

field.set(object, newFieldValue);

}

调用 modify(...)方法试图修改 person 的 name 属性

Person person = new Person();

modify(person, "name", "Michael");

System.out.println(person.name); //输出仍然是 Mike

为什么代码执行下来没问题,但输出又还是原来的值呢?但总是可以通过反射方式获取到修改后的新值。这就是 Java  编译器对 final 属型的内联优化,即编译时把该 final 的值直接放到了引用它的地方。即使是反射修改了该属性,但这种事后处理于事无补。

所以我在标题中所说如何有效的修改 final 属性值是指:反射修改了 final 属性值后能够在后续代码中使用修改后的值。

如果 Person 有个方法

public String getName() {

return name;

}

在前面代码反射修改了 name 属性后,getName()方法也仍然是返回 "Mike"。

那么 Java 会对什么类型的 final 值进行内联编译呢?它们基本类型 byte, char, short, int, long, float, double, boolean; 再加上 Literal String 类型(直接双引号字符串)。只要是不被编译器内联优化的 final 属性都可以通过反射有效的进行修改(修改后能使用到新的值)

String 类型比较特殊, 如果把 Person 类 name 属性改成用 new String("Mike")

public final String name = new String("Mike");

就能够有效的使用上面的反射代码修改 name 的值,最后

modify(person, "name", "Michael");

System.out.println(person.name) //输出就是 Michael 了

正如基本类型有相应的包装类型,可以把 new String("Mike")想像为 "Mike" 的包装类型。也确实是基本类型的 final 包装类型可以被反射有效的修改,new String("Mike") 也可以。

但我们要是在 IDE 中写成 new String("Mike") , 可能被告知  new String("")这种格式是冗余的,IDE 又会把它改成 "Mike",重而反射行为变得不正确。

还有,如果 final 属性值是通过构造函数传入的能不能有效的被修改,当然可以,因为它也不会被编译器内联优化。

总之一句话:只要不会被编译器内联优化的 final 属性就可以通过反射有效的进行修改 --  修改后代码中可使用到新的值

为加深印象,我们最后作一个较全面的测试

public class TestFinal {

public static void main(String[] args) throws Exception {

Person jordan = new Person("Chicago");

modify(jordan , "firstName", "Michael");

System.out.println(jordan .firstName); //Mike

modify(jordan , "lastName", "Michael");

System.out.println(jordan.lastName); //Michael

modify(jordan , "age", 51f);

System.out.println(jordan .age); //50.5

modify(jordan , "height", 1.98f);

System.out.println(jordan.height); //1.98

modify(jordan, "address", new Address("ccc", "ddd"));

System.out.println(jordan.address.line1); //ccc

modify(jordan , "city", "Miami");

System.out.println(jordan.city); //Miami

}

}

class Person {

public final String firstName = "Mike";

public final String lastName = new String("Jordan"); //可被有效修改

public final float age = 50.5f;

public final Float height = 1.99f; //可被有效修改

public final Address address = new Address("aaa", "bbb"); //可被有效修改

public final String city; //可被有效修改

public Person(String city) {

this.city = city;

}

}

final class Address {

public final String line1;

public final String line2;

public Address(String line1, String line2) {

this.line1 = line1;

this.line2 = line2;

}

}

我以前也有一人误区: 就是总以为加了 final 关键值,该属性就会被编译器内联优化,就不能用反射有效的进行修改。通过今天的梳理终于清晰的明白了:final 属性,只要不是基本类型和字面 String,就可以正常使用反射修改它的值。以前曾为了想反射修改某个 final 值还特意把  final  关键字给去掉,完全不用这么做。所以对于基本类型和字面 String, final 只是预示着它的值不能被正常的代码修改。

因此我们在声明 log 时

private static Logger log = LoggerFactory.getLogger(TestFinal.class);

private static final Logger log = LoggerFactory.getLogger(TestFinal.class);

性能上不会有什么差异,也不会因为多一个 final 而在任何使用到了 log 的地方内联它。只要留意基本类型和字面 String 就行了。

看完上述内容,你们对Java中final的属性值怎么利用反射机制进行修改有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

java 反射修改final变量_Java中final的属性值怎么利用反射机制进行修改相关推荐

  1. java final 实例_Java中final实现原理的深入分析(附示例)

    本篇文章给大家带来的内容是关于Java中final实现原理的深入分析(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. final在Java中是一个保留的关键字,可以声明成员变 ...

  2. java 中final修饰的变量_java中final修饰符的使用方法

    本文为大家分享了java中final修饰符的使用,供大家参考,具体内容如下 1.final修饰符的用法: final可以修饰变量,被final修饰的变量被赋初始值之后,不能对它重新赋值. final可 ...

  3. java final定义_Java中final关键字的用法

    final在Java中并不常用,然而它却为我们提供了诸如在C语言中定义常量的功能,不仅如此,final还可以让你控制你的成员.方法或者是一个类是否可被覆写或继承等功能,这些特点使final在Java中 ...

  4. java final 函数_JAVA中Final的用法

    1.         修饰基础数据成员的final 这是final的主要用途,其含义相当于C/C++的const,即该成员被修饰为常量,意味着不可修改.如java.lang.Math类中的PI和E是f ...

  5. java 从xml读变量_java – 如何从XML属性文件加载变量?

    我目前正在从Ant中的XML文件加载属性.但是,我想在for循环中执行当前的ant任务,同时每次为同一组属性加载新的XML属性文件. 我知道ant-contrib的var任务的存在,它允许我覆盖属性. ...

  6. java char 初始化为空格_java中char的初始值此代码运行后,char的初始值为空?为 爱问知识人...

    jdk官方教程里有写 Default Values(缺省值) ----------------------------------------------------- |Data Type |Def ...

  7. 【Matlab 控制】批量修改大型 Simulink 模型中模块的属性

    批量修改大型 Simulink 模型中模块的属性 一.通过Simulink自带的搜索 二.通过命令行进行搜索替换 三.使用Model Explorer编辑属性 在大型Simulink建模中,需要进行某 ...

  8. final关键字_Java中的final关键字

    我们都知道,Java是面向对象的语言,而面向对象有一种思想就是继承.但是有时候,出于某种原因,我们不希望我们的类.方法或者变量被继承或重写,这个时候,我们就需要final关键字来帮助我们达到这种效果. ...

  9. java原始类型和引用类型_Java中的8种原始类型

    java原始类型和引用类型 几年前,当我开始编辑Java Basics系列时,我认为将一些非常详细的信息拉到自己的帖子中是很有意义的. 这样,初学者的内容就更容易消化了. 首先,我将介绍有关Java的 ...

最新文章

  1. SQL学习之计算字段的用法与解析
  2. PAT 1069 1070 1071 1072
  3. CCF NOI1014 写评语
  4. 唯品会在 Flink 容器化与平台化上的建设实践
  5. 计算机科学导论考试A卷试题,09级计算机科学导论A卷答案
  6. Broadcast Receiver注意事项
  7. 使用实体框架返回数据表
  8. oracle开启未活动连接清理,Oracle inactive session的清理
  9. vb6 怎么把一个数组的 0 值 去掉_解决逆向查找问题?VLOOKUP、CHOOSE、IF,索引数组,轻松解决...
  10. php Excel报表,Excel报表生成的方案 PHPExcel
  11. 线性代数及其应用(原书第5版)
  12. 使用WireShark抓包对方QQ的ip地址(通过QQ电话)
  13. 百度文库和豆丁网的在线文档阅读功能
  14. 最新四方支付平台源码(PHP版本,完全开源)提供第四方支付系统搭建服务。
  15. 万字长文讲述我是怎样保送清华的 | 寒门学子奋斗史(四)
  16. 使用winserver2003配置DNS服务器
  17. 有赞搜索系统的架构演进
  18. 自己写的一个AI输入滤波函数
  19. 生成树协议STP(Spanning Tree Protocol)
  20. c语言对数组取反,C语言中按逆取反是什么意思

热门文章

  1. 2010年10大趋势
  2. matlab 任务分配粒子群算法
  3. 互联网快讯:人民币对美元汇率跌破7.2关口;长春新区一餐厅液化气泄漏引发爆炸
  4. qinglong青龙面板使用
  5. uniapp播放本地视频,循环播放第二遍会显示加载图标
  6. 怎么把照片的四个角变成圆的?
  7. JAVA定义一个银行帐户类BankAccount实现银行帐户的概念
  8. 如何在word中插入比较好看的代码
  9. js 的内存,堆和栈
  10. excel快速拆分合并的单元格并填充数据的方法