前言

以前写过一篇 Java 反射修改 final 属性值,本文将在这里重新温习一下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并发教程之volatile关键字详解
# Java多线程 volatile关键字详解
# Java volatile的适用场景实例详解
# Java中的关键字volatile详解
# Mybatis单个参数的if判断报异常There is no getter for property
# Java 用反射设置对象的属性值实例详解
# Java 采用反射获取class属性值的实现代码
# Java反射通过Getter方法获取对象VO的属性值过程解析
# 有个
# 可以通过
# 仍然是
# 到新
# 就可以
# 有一
# 就会
# 也有
# 我在
# 将在
# 就不
# 这就是
# 说了
# 一人
# 是指
# 不多
# 而在
# 于事无补
# 把它
# 它是
相关文章:
深圳网站制作平台,深圳市做网站好的公司有哪些?
浅析上传头像示例及其注意事项
Android自定义控件实现温度旋转按钮效果
如何在宝塔面板创建新站点?
javascript中对象的定义、使用以及对象和原型链操作小结
潮流网站制作头像软件下载,适合母子的网名有哪些?
,交易猫的商品怎么发布到网站上去?
如何通过云梦建站系统实现SEO快速优化?
建站之星伪静态规则如何正确配置?
Swift中switch语句区间和元组模式匹配
如何在IIS服务器上快速部署高效网站?
建站主机系统SEO优化与智能配置核心关键词操作指南
韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐
如何自定义建站之星模板颜色并下载新样式?
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)
建站主机是否等同于虚拟主机?
如何批量查询域名的建站时间记录?
江苏网站制作公司有哪些,江苏书法考级官方网站?
,网站推广常用方法?
浅谈Javascript中的Label语句
上海网站制作开发公司,上海买房比较好的网站有哪些?
一键制作网站软件下载安装,一键自动采集网页文档制作步骤?
为什么Go需要go mod文件_Go go mod文件作用说明
孙琪峥织梦建站教程如何优化数据库安全?
如何选择最佳自助建站系统?快速指南解析优劣
外贸公司网站制作哪家好,maersk船公司官网?
如何在IIS7上新建站点并设置安全权限?
测试制作网站有哪些,测试性取向的权威测试或者网站?
新网站制作渠道有哪些,跪求一个无线渠道比较强的小说网站,我要发表小说?
如何用已有域名快速搭建网站?
高性能网站服务器配置指南:安全稳定与高效建站核心方案
建站之星3.0如何解决常见操作问题?
建站主机选择指南:服务器配置与SEO优化实战技巧
大连 网站制作,大连天途有线官网?
logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?
个人摄影网站制作流程,摄影爱好者都去什么网站?
一键网站制作软件,义乌购一件代发流程?
已有域名和空间,如何快速搭建网站?
黑客如何利用漏洞与弱口令入侵网站服务器?
公司网站建设制作费用,想建设一个属于自己的企业网站,该如何去做?
北京网站制作公司哪家好一点,北京租房网站有哪些?
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
建站中国官网:模板定制+SEO优化+建站流程一站式指南
移民网站制作流程,怎么看加拿大移民官网?
教学网站制作软件,学习*后期制作的网站有哪些?
企业网站制作费用多少,企业网站空间一般需要多大,费用是多少?
javascript中的try catch异常捕获机制用法分析
网站制作服务平台,有什么网站可以发布本地服务信息?
如何正确选择百度移动适配建站域名?
*请认真填写需求信息,我们会在24小时内与您取得联系。