能否通过反射修改被 final 修饰的成员变量?

一、背景

日常磨刀

二、阅前须知知识点:

  1. 当final修饰的成员变量在定义的时候初始化值,反射就不能动态修改它的值了。
  2. 当final修饰的成员变量在定义的时候没有初始化值,就还能通过反射来动态修改它的值。
  3. 反射机制中的 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修饰,一样可以被通过反射之后进行修改

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值