java 反射修改修饰符_利用反射对修饰符为final的成员变量进行修改

假设我们有如下一个类,我们要利用反射来对其成员变量就行修改:

class Entity {

public int i = 1;

}

一般我们会这么做:

try {

Entity e = new Entity();

System.out.println("before: " + e.i);

Field f = Entity.class.getDeclaredField("i");

f.setInt(e, 2);

// 或者这样

//f.set(e, 2);// java会自动装箱拆箱

System.out.println("after: " + e.i);

} catch (Exception e) {

e.printStackTrace();

}

结果输出:

before: 1

after: 2

但是如果我们的成员变量是final呢?

class Entity {

public final int i = 1;

}

我们再用上面的方式来进行修改值,发现出异常了:

java.lang.IllegalAccessException: Can not set final int field com.test.Entity.i to (int)2

那我们该怎么办呢?我们可以修改成员变量的final修饰符,使其变为public int i = 1;具体方法如下:

try {

Entity e = new Entity();

System.out.println("before: " + e.i);

Field f = Entity.class.getDeclaredField("i");

Field modifiersField = Field.class.getDeclaredField("modifiers");

modifiersField.setAccessible(true);

// 输出17:表示修饰符为:public final

System.out.println(f.getModifiers());

/* 这里就是要修改修饰符了,至于为什么是f.getModifiers() & ~Modifier.FINAL,大家看一下Modifier的源码就知道了*/

modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);

// 输出1:表示修饰符已经被修改为:public

System.out.println(f.getModifiers());

f.setAccessible(true);

f.setInt(e, 2);

//f.set(e, 3);

System.out.println("after: " + e.i);

} catch (Exception e) {

e.printStackTrace();

}

没有抛出异常了,但是确没有出现我们想要的结果,输出为:

before: 1

17

1

after: 1

这是为什么呢?我们稍微修改下Entity的代码如下:

class Entity {

public final Integer i = 1;

}

然后再执行,发现结果已经被修改了:

before: 1

17

1

after: 3

说明我可以对对象数据类型进行修改,而不能对基本数据类型进行修改

我们再来试试String类型的:

class Entity {

public final String s = "a";

}

try {

Entity e = new Entity();

System.out.println("before: " + e.s);

Field f = Entity.class.getDeclaredField("s");

Field modifiersField = Field.class.getDeclaredField("modifiers");

modifiersField.setAccessible(true);

System.out.println(f.getModifiers());

modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);

System.out.println(f.getModifiers());

f.setAccessible(true);

//f.setInt(e, 2);

f.set(e, "b");

System.out.println("after: " + e.s);

} catch (Exception e) {

e.printStackTrace();

}

结果输出:

before: a

17

1

after: a

咦?竟然木有改变?

我们再对Entity稍微改动下:

class Entity {

public final String s = new String("a");

}

结果输出:

before: a

17

1

after: b

修改成功,至于为什么会这样,那得问java虚拟机了

好了,总结一下,对于final修改的成员变量,基本数据以及public final String s = "a";这种方式不可被修改

而对于对象数据类型是可以突破final限制进行修改的,但是一般我们也很少会这么用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值