Java反射-修改private final成员变量值,你知道多少?
大家都知道使用java反射可以在运行时动态改变对象的行为,甚至是private final的成员变量,但并不是所有情况下,都可以修改成员变量。今天就举几个小例子说明。
首先看下对基本类型的修改:
/**
* @author Cool-Coding 2018/5/15
*/
public class ReflectionUsage {private final int age=18; public int getAge(){
return age;
}
}
测试代码:
import java.lang.reflect.Field; /**
* @author Cool-Coding 2018/5/15
*/
public class ReflectionTest {
public static void main(String[] args){ try {
Class reflectionUsage = Class.forName("practise.practise.ReflectionUsage");
ReflectionUsage o = (ReflectionUsage)reflectionUsage.newInstance();
Field age = reflectionUsage.getDeclaredField("age");
age.setAccessible(true);
age.set(o,68);
age.setAccessible(false);
System.out.println(o.getAge());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}catch (IllegalAccessException | InstantiationException e){ }
}
}
运行结果:18
此时无法修改成员变量age.
如果将初始化age放到构造函数中会如何呢:
/**
* @author Cool-Coding 2018/5/15
*/
public class ReflectionUsage {private final int age; public ReflectionUsage(){
this.age=18;
} public int getAge(){
return age;
}
}
再执行RefectionTest会发生什么呢?会发现结果变成了68。
为什么会发生这种情形呢?看一下这两个情况下生成的class文件有什么不同:
直接初始化:
public class ReflectionUsage {
private final int age = 18;
public ReflectionUsage() {
}
public int getAge() {
return 18;
}
}
构造函数中初始化:
public class ReflectionUsage {
private final int age = 18;
public ReflectionUsage() {
}
public int getAge() {
return this.age;
}
}
可以看出如果直接初始化时,经过编译后getAge方法直接返回常量值,而在构造函数中初始化时,返回的是this.age变量的值。
再看下对String类型的修改:
/**
* @author Cool-Coding 2018/5/15
*/
public class ReflectionUsage {
private final String reflectionString="reflectionString";
public String getReflectionString(){
return reflectionString;
}
}
测试代码:
import java.lang.reflect.Field; /**
* @author Cool-Coding 2018/5/15
*/
public class ReflectionTest {
public static void main(String[] args){
try {
Class reflectionUsage = Class.forName("practise.practise.ReflectionUsage");
ReflectionUsage o = (ReflectionUsage)reflectionUsage.newInstance();
Field reflectionString = reflectionUsage.getDeclaredField("reflectionString");
reflectionString.setAccessible(true);
reflectionString.set(o,"newReflectionString");
reflectionString.setAccessible(false);
System.out.println(o.getReflectionString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}catch (IllegalAccessException | InstantiationException e){ } }
}
运行结果:reflectionString
如果将初始化reflectionString放到构造函数中又如何呢?
/**
* @author Cool-Coding 2018/5/15
*/
public class ReflectionUsage {
private final String reflectionString;
public ReflectionUsage(){
this.reflectionString="reflectionString";
}
public String getReflectionString(){
return reflectionString;
}
}
运行结果:newReflectionString
为什么运行结果不同呢,来看下class文件:
直接初始化:
public class ReflectionUsage {
private final String reflectionString = "reflectionString";
public ReflectionUsage() {
}
public String getReflectionString() {
return "reflectionString";
}
}
构造函数中初始化:
public class ReflectionUsage {
private final String reflectionString = "reflectionString";
public ReflectionUsage() {
}
public String getReflectionString() {
return this.reflectionString;
}
}
可以看出跟基本类型相似,直接初始化时,编译器会将reflectionString出现的地方,替换成常量值,而构造函数中初始化不替换。
再看下对Integer的修改:
/**
* @author Cool-Coding 2018/5/15
*/
public class ReflectionUsage {
private final Integer age=18; public Integer getAge(){
return age;
}
}
测试代码:
import java.lang.reflect.Field; /**
* @author Cool-Coding 2018/5/15
*/
public class ReflectionTest {
public static void main(String[] args){
try {
Class reflectionUsage = Class.forName("practise.practise.ReflectionUsage");
ReflectionUsage o = (ReflectionUsage)reflectionUsage.newInstance();
Field reflectionString = reflectionUsage.getDeclaredField("age");
reflectionString.setAccessible(true);
reflectionString.set(o,68);
reflectionString.setAccessible(false);
System.out.println(o.getAge());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}catch (IllegalAccessException | InstantiationException e){ }
}
}
运行结果:
可以看出直接初始化private final Integer age变量后,不像基本类型和String类型一样不能修改,原因是什么呢,看下class文件。
public class ReflectionUsage {
private final Integer age = Integer.valueOf(18);
public ReflectionUsage() {
}
public Integer getAge() {
return this.age;
}
}
可以看到编译器并未将getAge中变量替换成常量。
看到对Integer赋值时,编译器进行了自动装箱,那如果初始化String变量时,使用String.value()方式时,能否被修改呢,来看一下。
/**
* @author Cool-Coding 2018/5/15
*/
public class ReflectionUsage {
private final String reflectionString = String.valueOf("reflectionString"); public ReflectionUsage() {
} public String getReflectionString() {
return this.reflectionString;
}
}
运行结果:newReflectionString
可以看出,reflectionString的值被修改了,看下class文件:
package practise.practise;
public class ReflectionUsage {
private final String reflectionString = String.valueOf("reflectionString");
public ReflectionUsage() {
}
public String getReflectionString() {
return this.reflectionString;
}
}
可见编译器并未替换getReflectionString方法中的变量。
如果在构造函数中初始化Integer类型变量呢?
public class ReflectionUsage {
private final Integer age;
public ReflectionUsage() {
this.age=18;
}
public Integer getAge() {
return this.age;
}
}
运行结果:
age值也被改变了,看下class文件:
public class ReflectionUsage {
private final Integer age = Integer.valueOf(18);
public ReflectionUsage() {
}
public Integer getAge() {
return this.age;
}
}
生成的class文件与直接初始化是一样的。
总结:
final可以修改类,变量,方法,表示不可继承,不可修改,不可覆盖(override),这里讨论了使用反射修改private final修饰的成员变量情况,当private final修改直接初始化的基本类型或String(注意不能使用String.valueOf()初始化)时,使用反射无法修改变量值,其它情况下可以修改。这也告诉我们在平时开发时,如果想定义常量请在基本类型int或String类型前加private final修饰,这样编译器会在编译时将这些变量出现的地方替换成常量,以免被恶意修改。
Java反射-修改private final成员变量值,你知道多少?的更多相关文章
- java 反射实现2个int变量值的交换
import java.io.*;import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; ...
- Java反射-修改字段值, 反射修改static final修饰的字段
反射修改字段 咱们从最简单的例子到难, 一步一步深入. 使用反射修改一个private修饰符的变量name 咱们回到主题, 先用反射来实现一个最基础的功能吧. 其中待获取的name如下: public ...
- MFC一个类访问另一个类成员对象的成员变量值
MFC中一个类要访问另外一个类的的对象的成员变量值,这就需要获得原来那个类对象的指针,其实有好几种方法都可以实现. 比如维护一个单例模式.设置静态变量等等.我们这里举个列子,实现多个类之间的相互访问. ...
- MFC 一个类訪问还有一个类成员对象的成员变量值
作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/35263857 MFC中一个类要訪问另外一个类的的对象的成员变量值,这就须要获得 ...
- 通过JAVA反射修改JDK1.6*当中DNS缓存内容
时间 2012-05-28 17:09:03 Taobao QA Team原文 http://qa.taobao.com/?p=15523 为了实现性能压测时的域名动态绑定功能,尝试通过java反 ...
- Java 反射修改类的常量值、静态变量值、属性值
前言 有的时候,我们需要修改一个变量的值,但变量也许存在于 Jar 包中或其他位置,导致我们不能从代码层面进行修改,于是我们就用到了下面的场景,通过反射来进行修改变量的值. 定义一个实体类 class ...
- 反射修改 static final 变量
一.测试结论 static final 修饰的基本类型和String类型不能通过反射修改; 二.测试案例 @Test public void test01() throws Exception { s ...
- java反射修改静态方法的值setAccessible
这几天闲来无事.在网上看了一个题目,相信大家都知道这个题目 static void change(String str){ str="welcome"; ...
- java反射修改final变量
private void updateFinalModifiers(Field field) throws NoSuchFieldException, IllegalAccessException { ...
随机推荐
- python3爬虫 - cookie登录实战
http://blog.csdn.net/pipisorry/article/details/47948065 实战1:使用cookie登录哈工大ACM网站 获取网站登录地址 http://acm.h ...
- [leetcode]经典算法题- String to Integer (atoi)
题目描述: 把字符串转化为整数值 原文描述: Implement atoi to convert a string to an integer. Hint: Carefully consider al ...
- H5学习之旅-H5与Php交互(12)
1.首先介绍PHP开发环境的搭建 ,在Google搜apachefriends,会有xampp的下载链接,这个工具集成了apache的很多服务 2.搭建php的编辑环境,选取eclipse安装php插 ...
- Google地球查看香港地形
12月1号要去香港.为此需要先了解一下香港的情况.以前只知道用Google地球看别人照的照片(或者是全景照),这次无意间发现了它一个很强大的功能:立体的呈现一个地区的地形.对于像香港这样的多山地区来说 ...
- 《java入门第一季》之面向对象(如何使用帮助文档)
1:打开帮助文档 2:点击显示,找到索引,看到输入框 3:知道你要找谁?以Scanner举例 4:在输入框里面输入Scanner,然后回车 5:看包 java.lang包下的类不需要导入包,其他的全部 ...
- java的参数传递与内存分配问题
本文可作为北京尚学堂java课程的学习笔记. 看下面这段代码. class BirthDate { private int day; private int month; private int ye ...
- 用简单的C语言实现多任务轮流切换(模拟操作系统线程机制)
最近在看linux内核的进程调度算法,也写了不少的内核注释,也参考了鸿哥的单片机框架,代码注释就开源在我的CSDN的git代码库里,有兴趣的可以去瞧瞧. 突发奇想,想到了既然单片机能够实现,那么我用标 ...
- linux服务搭建----ftp与ftp yum源搭建
ftp服务 如果没有ftp yum -y install vsftpd (前提是你在有yum源的情况下才可以使用这条命令) service vsftpd resta ...
- linux下将eclipse项目转换为gradle项目
本文针对于在linux环境下,不使用eclipse而把一个eclipse项目转换为gradle默认结构的项目的情况,脚本可能在mac下也适用,未验证. windows中的转换问题,以及使用eclips ...
- The 1st tip of DB Query Analyzer
The 1st tip of DB Query Analyzer Ma Genfeng (Guangdong Unitoll Services incorporate ...