在Java中,我们都知道对象判断使用==来进行地址判断,使用String的equals方法或者其它判断方法来进行内容的判断。虽然网络上关于这个坑的文章已经有很多了,但还是忍不住想在知乎上面分享一下,那么今天就来揭露以下Java中的int装箱类型Integer的一个坑人之处。
首先我们做个简单的测试,如下图,各位猜一下输出结果是什么样的。
结果如下图:
后面三个为true看起来都很正常,但为什么前两个Integer对象比对就是false呢,是不是两者的对象地址不同了?这里需要我们深一步探究这个问题。
首先我们知道,Integer在字面量进行赋值的时候使用到了这个类里的一个valueOf方法(具体原因使用Java反编译可得知),而这个方法上面有一段文档注释,这里我们翻译一下得到如下内容:
返回表示指定int值的整数实例。如果不需要新的整数实例,通常应优先使用该方法而不是构造函数整数(int),因为通过缓存频繁请求的值,该方法可能会产生显著更好的空间和时间性能。此方法将始终缓存-128到127(含)范围内的值,并且可能缓存此范围之外的其他值。
这个翻译内容里面提到了缓存,那么这个缓存是何方神圣呢,这里我们再往底层代码看一下。
看到上图红圈的代码得知,我们定义的数值如果在一个范围内的话,那么我们得到的Integer对象来源不一样了就。而这个IntegerCache类是个什么?这里我们点进去看一下。
关于这个内部类的代码就这么点,从上图我们可以得知这个范围是在-128和127之间,而在这个变量low和high下面还有一个数组的定义,这个数组的内容从上图下方的cache = new Integer[(high - low) + 1];往下看。不难看出这个数组会将上述范围内的数值全部存起来,而我们根据上上图的红圈内容的if判断可以得知如果我们给Integer赋值范围在这个IntegerCache范围之内的话那么会获取这个缓存里已经定义好的其中一个Integer对象返回给你,所以这个范围内的Integer使用==比较的话就是true,否则为false。官方如此做法是为文章上面所说的,在项目加载之初就事先定义好这些数值对象,而后需要用的话就可以节省一定的性能开销了。
该文章仅供参考,如有错误或缺漏欢迎各位指点迷津。