利用反射修改final数据域
当final修饰一个数据域时,意义是声明该数据域是最终的,不可修改的。常见的使用场景就是eclipse自动生成的serialVersionUID一般都是final的。
另外还可以构造线程安全(thread safe)的immutable类,比如String,其数据域都是final的。这些使用场景都建立在final不可修改这个条件上,但是,反射可以打破这一切。
1.利用反射修改final数据域
首先,构造一个Person类,里面有个final字段NAME。我们尝试着修改这个字段。顺利的出乎意料。
public class Person {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Person p = new Person();
Field field = p.getClass().getDeclaredField("NAME");
field.setAccessible(true);
field.set(p,"Hello");
System.out.println(field.get(p));
//p.printName();
}
private final String NAME = "Clive";
public Person() {
}
public void printName() {
System.out.println(NAME);
}
}
/***************
console print:
Hello
***************/
2.内联与内联消除
NAME数据域如此简单的就被修改了,final真是太"不安全了"! 但是,当我们调用p.printName() 时,控制台打印的却是"Clive"字符串。这是因为JVM做了优化处理, 当一个数据域被final修饰,那就表明这个数据域是常量,JVM会把所有NAME数据域出现的地方全部用"Clive"替换掉, 比如 printName() 方法其实被优化成了这样。
public void printName() { System.out.println("Clive"); }
所以,要想不被自动优化,就要把代码弄得复杂点,如下
public class Person {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Person p = new Person();
Field field = p.getClass().getDeclaredField("NAME");
field.setAccessible(true);
field.set(p,"Hello");
System.out.println(field.get(p));
p.printName();
}
private final String NAME =(null!=null?"Clive":"Clive"); //声明时即初始化
public Person() {
//或者,在这里设置NAME数据域的值
//NAME="Clive";
}
public void printName() {
System.out.println(NAME);
}
}
/***************
console print:
Hello
Hello
***************/
结果见 console print,顺利消除了优化,final字段最终被修改了!
3.修改static final数据域
如果在NAME字段再增加一个static关键字修饰,然后再用反射修改的话就不行了, 会抛出异常
java.lang.IllegalAccessException: Can not set static final int field ...
这时,修改Field中的modifiers数据域,清除代表final的那个bit,才可以成功修改。
public class Person {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Person p = new Person();
Field field = p.getClass().getDeclaredField("NAME");
Field modifiers = field.getClass().getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);//fianl标志位置0
field.set(p,"Hello");
System.out.println(field.get(p));
p.printName();
}
private final String NAME =(null!=null?"Clive":"Clive");
public Person() {
}
public void printName() {
System.out.println(NAME);
}
}
/**************
console print:
Hello
Hello
**************/
总结
这个知识点感觉知道就好,平时还是不要修改final数据域的好 :)
引用
1.https://www.oschina.net/question/1245392_159103
2.https://github.com/jOOQ/jOOR
利用反射修改final数据域的更多相关文章
- .NET 利用反射将对象数据添加到数据库
.NET 利用反射将对象数据添加到数据库 一些小型的项目,在不使用其他的框架(LINQ,NHibernate,EF等等框架)的前提下,这时候一些反复的增删改查就会让我们感到极其的繁琐,厌烦,为了避 ...
- winform中利用反射实现泛型数据访问对象基类(3)
继续完善了几点代码 满足没有主键的情况下使用 并且完善实体字段反射设置value时的类型转换 /// <summary> /// DAO基类 实体名必须要与数据表字段名一致 /// < ...
- 使用反射修改final属性
情型1:static final属性,无法修改其值. package m5.d7; import java.lang.reflect.Field; public class FieldTest { p ...
- winform中利用反射实现泛型数据访问对象基类(2)
在1的基础上做了一点改进 参数化处理 看上去更简洁 无主键情况下 update 方法需要改进 insert delete没有问题 /// <summary> /// DAO基类 ...
- winform中利用反射实现泛型数据访问对象基类(1)
考虑到软件使用在客户端,同时想简化代码的实现,就写了一个泛型的数据访问对象基类,并不是特别健全,按道理应该参数化的方式实现insert和update,暂未使用参数化,抽时间改进. /// <su ...
- java反射修改final变量
private void updateFinalModifiers(Field field) throws NoSuchFieldException, IllegalAccessException { ...
- jav利用反射修改类的静态变量
有Student这个类: public class Student { private static String schoolName=""; private static St ...
- Java反射-修改字段值, 反射修改static final修饰的字段
反射修改字段 咱们从最简单的例子到难, 一步一步深入. 使用反射修改一个private修饰符的变量name 咱们回到主题, 先用反射来实现一个最基础的功能吧. 其中待获取的name如下: public ...
- Java——利用反射机制将表单数据自动填充到JavaBean中
以一个案例介绍反射机制的一种常见的使用场景,以及具体实现. 1.本文案例 在编写Java Web应用程序时,使用表单提交数据是一个必不可少的环节,后台对于前台使用表单提交的数据需要能够从请求中解析,并 ...
随机推荐
- 牛客小白月赛2 D 虚虚实实 【欧拉图】【连通图】
链接:https://www.nowcoder.com/acm/contest/86/D来源:牛客网 题目描述 震为雷,临危不乱,亨通畅达:巽为风,柔顺伸展,厚载万物. 震卦:洊雷,震,君子以恐惧修省 ...
- 浅谈MySQL字符集
Preface MySQL use character set & collation to organize the different charater.It provid ...
- Android和IOS网页不一致汇总
1.input type=text 内容输入框的不一致,ios会默认给输入框添加自己的样式,导致在横向的输入框长度精准控制的时候,ios的输入框一般都比android上要长一点,还有内部阴影 解决此问 ...
- (转)数据库老兵:NewSQL才是未来
编者按:在数据库技术领域,Michael Stonebraker几乎是无人不知无人不晓的人物.现年70岁的Stonebraker不仅是Ingres和PostgreSQL的创始人,同时在Informix ...
- Hive的数据库和表
本文介绍一下Hive中的数据库(Database/Schema)和表(Table)的基础知识,由于篇幅原因,这里只是一些常用的.基础的. Hive的数据库和表 先看一张草图: Hive结构 从图上可以 ...
- 17-比赛1 C - Binary Nim (栈的游戏)
题目描述 Tweedle-Dee 和 Tweedle-Dum 正在进行一场激烈的二进制 Nim 游戏.这是你没有玩过的船新版本,游戏包含 N 个栈,每个栈只包含 0 和 1 的元素.就像一般的 Nim ...
- ABAP News for Release 7.51 – ABAP CDS Client Handling
Open SQLは自動的クライアント処理をサポートしています. Open SQLでクライアント依存のデータソースにアクセスする時.デフォルトでは現在のクライアントのデータだけが考慮されます. クライア ...
- Personal Collection
1.常用网站 序号 网址 标题 1 https://www.oschina.net/ 开源软件 2 http://tool.oschina.net/ 开发常用工具网站 3 https://docs.o ...
- io编程,python
IO在计算机中指Input/Output,也就是输入和输出. Stream(流): 可以把流想象成一个水管,数据就是水管里的水,但是只能单向流动.Input Stream就是数据从外面(磁盘.网络)流 ...
- python基础之列表、元组和字典
列表 列表定义:[]内以逗号分隔,按照索引,存放各种数据类型,每个位置代表一个元素 特性: 1.可存放多个值 2.可修改指定索引位置对应的值,可变 3.按照从左到右的顺序定义列表元素,下标从0开始顺序 ...