java 反射修改final变量_Java中final的属性值怎么利用反射机制进行修改
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的属性值怎么利用反射机制进行修改相关推荐
- java final 实例_Java中final实现原理的深入分析(附示例)
本篇文章给大家带来的内容是关于Java中final实现原理的深入分析(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. final在Java中是一个保留的关键字,可以声明成员变 ...
- java 中final修饰的变量_java中final修饰符的使用方法
本文为大家分享了java中final修饰符的使用,供大家参考,具体内容如下 1.final修饰符的用法: final可以修饰变量,被final修饰的变量被赋初始值之后,不能对它重新赋值. final可 ...
- java final定义_Java中final关键字的用法
final在Java中并不常用,然而它却为我们提供了诸如在C语言中定义常量的功能,不仅如此,final还可以让你控制你的成员.方法或者是一个类是否可被覆写或继承等功能,这些特点使final在Java中 ...
- java final 函数_JAVA中Final的用法
1. 修饰基础数据成员的final 这是final的主要用途,其含义相当于C/C++的const,即该成员被修饰为常量,意味着不可修改.如java.lang.Math类中的PI和E是f ...
- java 从xml读变量_java – 如何从XML属性文件加载变量?
我目前正在从Ant中的XML文件加载属性.但是,我想在for循环中执行当前的ant任务,同时每次为同一组属性加载新的XML属性文件. 我知道ant-contrib的var任务的存在,它允许我覆盖属性. ...
- java char 初始化为空格_java中char的初始值此代码运行后,char的初始值为空?为 爱问知识人...
jdk官方教程里有写 Default Values(缺省值) ----------------------------------------------------- |Data Type |Def ...
- 【Matlab 控制】批量修改大型 Simulink 模型中模块的属性
批量修改大型 Simulink 模型中模块的属性 一.通过Simulink自带的搜索 二.通过命令行进行搜索替换 三.使用Model Explorer编辑属性 在大型Simulink建模中,需要进行某 ...
- final关键字_Java中的final关键字
我们都知道,Java是面向对象的语言,而面向对象有一种思想就是继承.但是有时候,出于某种原因,我们不希望我们的类.方法或者变量被继承或重写,这个时候,我们就需要final关键字来帮助我们达到这种效果. ...
- java原始类型和引用类型_Java中的8种原始类型
java原始类型和引用类型 几年前,当我开始编辑Java Basics系列时,我认为将一些非常详细的信息拉到自己的帖子中是很有意义的. 这样,初学者的内容就更容易消化了. 首先,我将介绍有关Java的 ...
最新文章
- SQL学习之计算字段的用法与解析
- PAT 1069 1070 1071 1072
- CCF NOI1014 写评语
- 唯品会在 Flink 容器化与平台化上的建设实践
- 计算机科学导论考试A卷试题,09级计算机科学导论A卷答案
- Broadcast Receiver注意事项
- 使用实体框架返回数据表
- oracle开启未活动连接清理,Oracle inactive session的清理
- vb6 怎么把一个数组的 0 值 去掉_解决逆向查找问题?VLOOKUP、CHOOSE、IF,索引数组,轻松解决...
- php Excel报表,Excel报表生成的方案 PHPExcel
- 线性代数及其应用(原书第5版)
- 使用WireShark抓包对方QQ的ip地址(通过QQ电话)
- 百度文库和豆丁网的在线文档阅读功能
- 最新四方支付平台源码(PHP版本,完全开源)提供第四方支付系统搭建服务。
- 万字长文讲述我是怎样保送清华的 | 寒门学子奋斗史(四)
- 使用winserver2003配置DNS服务器
- 有赞搜索系统的架构演进
- 自己写的一个AI输入滤波函数
- 生成树协议STP(Spanning Tree Protocol)
- c语言对数组取反,C语言中按逆取反是什么意思