一、背景
日常磨刀
二、阅前须知知识点:
- 当final修饰的成员变量在定义的时候初始化值,反射就不能动态修改它的值了。
- 当final修饰的成员变量在定义的时候没有初始化值,就还能通过反射来动态修改它的值。
- 反射机制中的 setAccessible 代表的权限含义
三、举例(这里只用基本数据类型和包装类来讨论)
1、不能被修改的情况,直接贴代码讲
//创建一个实体类
public class Demo {
private final int info = 123;
public int getInfo() {
return info;
}
}
//反射修改的代码区域
public class TestFianl {
public static void main(String[] args) {
try {
test();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static void test() throws NoSuchFieldException, IllegalAccessException {
Demo demo = new Demo();
System.out.println("反射修改之前 Demo 实例的值:"+demo.getInfo());
Field field = demo.getClass().getDeclaredField("info");
field.setAccessible(true);//灵魂语句
field.set(demo, 789);
System.out.println("反射修改之后 Field 实例的值:"+field.get(demo));
System.out.println("反射修改之后 Demo 实例的值:"+demo.getInfo());
}
}
//输出结果为:
反射修改之前 Demo 实例的值:123
反射修改之后 Field 实例的值:789
反射修改之后 Demo 实例的值:123
解释:
1、注意这里的 修改的 成员变量 info 是被基本数据类型 int 修饰的
2、编译的时候 被final修饰的成员变量会被优化,所有用到该变量的地方都被替换成了变量的内容 123
第二句话解释看以下Demo 类反编译的代码
public class Demo
{
private final int info = 123;
public int getInfo() {
return 123;//直接返回了 123 这个内容 而不是 info 这个变量
}
}
2、能被修改的情况
//创建一个实体类
public class Demo {
private final Integer info = 123;
public Integer getInfo() {
return info;
}
}
//反射修改的代码区域 和 1 中的没有区别
public class TestFianl {
public static void main(String[] args) {
try {
test();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static void test() throws NoSuchFieldException, IllegalAccessException {
Demo demo = new Demo();
System.out.println("反射修改之前 Demo 实例的值:"+demo.getInfo());
Field field = demo.getClass().getDeclaredField("info");
field.setAccessible(true);//灵魂语句
field.set(demo, 789);
System.out.println("反射修改之后 Field 实例的值:"+field.get(demo));
System.out.println("反射修改之后 Demo 实例的值:"+demo.getInfo());
}
}
//输出结果为:
反射修改之前 Demo 实例的值:123
反射修改之后 Field 实例的值:789
反射修改之后 Demo 实例的值:789
解释:
1、注意这里的 修改的 成员变量 info 是被 包装类 Integer 修饰的
2、定义的时候并没有初始化值,getInfo方法返回的是info这个变量
以下Demo 类反编译的代码
public class Demo
{
private final Integer info = Integer.valueOf(123);//定义的时候检查再初始化了值
public Integer getInfo() {
return this.info;
}
}
四、总结
所以成员变量在定义的时候没有初始化值的时候,就算用final修饰,一样可以被通过反射之后进行修改