JAVA中的final域真的不可以被修改吗?

final在java中的语义就是常量的意思,这个我们大家都知道。

但是这个常量其实按照C语言的思想来说的话其实是相当于一个指针指向一个地址,然后指针的值不能被改变,也就是是说这个指针变量一直指向这块内存空间,但是这这块内存空间的值是可以被改变的。我们今天就来尝试一下去改变一下这个内存空间的值

 

final Integer num = 321;

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    T t = new T();
    System.out.println(t.num);
    Field field = T.class.getDeclaredField("num");
    field.set(t,32132);
    System.out.println(t.num);
}

结果

说是不能设置final域的字段,加上 field.setAccessible(true)试试看

final Integer num = 321;

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    T t = new T();
    System.out.println(t.num);
    Field field = T.class.getDeclaredField("num");
    field.setAccessible(true);
    field.set(t,32132);
    System.out.println(t.num);
}

这样看来,final域也是可以被反射修改的嘛。

 

刚才尝试是引用类型,现在试试基本类型

final int num = 321;

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    T t = new T();
    System.out.println(t.num);
    Field field = T.class.getDeclaredField("num");
    field.setAccessible(true);
    field.set(t,32132);
    System.out.println(t.num);
}

运行成功了,但是值没有被改变 

 

 

尝试反射去获取一下值

final int num = 321;

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    T t = new T();
    System.out.println(t.num);
    Field field = T.class.getDeclaredField("num");
    field.setAccessible(true);
    field.set(t,32132);
    System.out.println(t.num);
    System.out.println(field.get(t));
}

反射的值是被修改了的 

 

为什么出现了这种情况,猜想应该是Java对基本类型的final域进行了什么优化处理,导致了不能被修改。

我们来看看其对java做了什么处理:

int num = 321;

public static void main(String[] args) {
    T t = new T();
    int c = t.num;
}

对应的字节码指令 

final int num = 321;

public static void main(String[] args) {
    T t = new T();
    int c = t.num;
}

对应的字节码 

 

可以看出区别还是非常明显的,没有加final的,获取对应的属性值的时候是通过getfield去获取对应的值,但是加上final的,没有通过该getfield获取属性值,而是直接在操作数中带上了321,猜想这可能就是编译器进行的优化,他发现该字段是基本类型且被final修饰,反正是只读的,就直接将321写入到了字节码指令中,而不用每次去读取。所以,都写入字节码指令了,你修改他对象上的值,有什么用?这个对象中的num域还是存在的,所以我们反射还是能进行修改,反射修改之后也能获取到被修改之后的值,但是问题在于,我们直接t.num这样生成的字节码指令,根本就不会去实例域中取值!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值