反射交换两个值的大小引发的思考

版权声明:分享,转载原创文章,麻烦注明一下出处~谢谢 https://blog.csdn.net/sc9018181134/article/details/79721723

发现问题:

最近在学习java的时候在java群里面看到一个问题,就是用反射来实现两个值的交换,然后结果没有按群友的预期去执行.群里的代码如下:
原程序
群友想的结果是a=1,b=2;a=2,b=1;
然而结果是
这里写图片描述
然后就觉得很奇怪,交换完以后,a,b都变成了2.

问题探究过程

(和群友一起讨论出来的,一开始自己也觉得很奇怪,涉及到java的自动装箱和Integer类的源码设计问题):
1.首先将源代码反编译,推荐使用jad下载地址,eclipse和idea上也有相应的插件.反编译出来如下:
这里写图片描述
可以看到Integer a = 1;这种类似的地方进行了自动装箱;int tmp = num1,进行了自动拆箱.分别使用的是valueOf(),intValue();
2.然后我们去查看Integer的源码发现,如下图:
这里写图片描述
这里写图片描述
这里写图片描述
    (1).Integer类里面有个叫IntegerCache的Integer类型的缓存数组;
    (2).cache里面的值从图中可以看出是从-128到127,一共256个整型数值;
    (3).我们使用的Integer的值来源于final类型的value,正常情况是不可变的,但是用了反射,设置了field.setAccessible(true);就可以改变value的值,群友也正是想用反射来改变value的值,从而达到交换数值的目的.
3.在自动装箱valueOf()打了断点,在进行第二次的交换field.set(num2, tmp)的时候如图:
这里写图片描述
发现cache的129位置原来应该是1的值,变成了2.所以内存中的Integer的cache[129]的值都变成了2,因此结果b=2,tmp=2.

结果分析:

1.field.set(num1, num2)的时候,反射将原本value=1的IntegerCache中的cache[129]的值修改为了2.所以在field.set(num2, tmp)的时候,是将num2(cache[129]等于2)的值赋值给了tmp(也变为2).
2.因为缓存数组的大小是在-128-127之间,所以我们将a,b的值都大于127的时候用反射来交换数值的大小是不会出问题的,因为不在缓存数组中的数值,会重新生成.如图:
这里写图片描述
结果:
这里写图片描述
这样交换是没有问题的.

自我总结:

一.是反射不要乱用,可能会有你想不到的后果;
二是涉及到自动装箱的可能会有坑,最好使用Integer i = new Integer(‘数字’);这样就不会有Cache数组的坑,因为是重新新建了一个Integer的对象.

猜你喜欢

转载自blog.csdn.net/sc9018181134/article/details/79721723
今日推荐