为了让int类型的方法参数可以接收null值,通常我们会把设置成int类型的包装类型Integer,我们的故事便从这里开始,我们先来看一段代码:
public class Demo { public static void main(String[] args) { test(10,10); test(128,128); } public static void test(Integer i,Integer j){ if(i == null || j == null){ return; } if(i == j){ System.out.println("成功!"); }else { System.out.println("失败!"); } } }控制台输出:
成功! 失败!My God,为什么第2个输出失败,而不是成功!崩溃。。。。
我们猜测是Integer类导致的,我们知道Integer是int类型的包装类,这里就涉及到Java的自动装箱与拆箱了。那什么是自动装箱与拆箱呢?
从Java SE5开始就提供了自动装箱与拆箱的特性。装箱就是自动将基本数据类型转换为包装器类型;拆箱是自动将包装器类型转换为基本数据类型。如下所示:
Integer m = 100; //装箱 int y = m; //拆箱我们以Integer类为例,下面先看一段代码:
public class Case { public static void main(String[] args) { Integer m = 100; int y = m; } }这段代码反编译的字节码如下:
从反编译得到的字节码内容可以看出,在装箱的时候自动调用的是Integer的valueOf(int)方法,而在拆箱的时候自动调用的是Integer的intValue方法。其他的基本类型也类似,感兴趣的小伙伴可以去尝试一下!
接下来我们就需要查看Integer.valueOf方法的源码,我们来看一下:
从上我们能够看出,这里用到了IntegerCache,接下来我们来看一下IntegerCache类,我们发现IntegerCache是Integer的一个内部类:
我们可以从源码中发现,原来Integer类里面默认自带缓存,缓存范围默认为[-128-127]。这样我们就能解释上面例子的情况了,10在缓存范围内,所以两次返回的都是相同的对象,而128不在缓存范围内,所以每次都会新建一个Intger对象,这样就导致两个对象不等。
要解决我们上面的问题,我们只需要使用Integer.intValue()方法就可以了,修改后的代码如下:
public class Demo { public static void main(String[] args) { test(10,10); test(128,128); } public static void test(Integer i,Integer j){ if(i == null || j == null){ return; } if(i.intValue() == j.intValue()){ System.out.println("成功!"); }else { System.out.println("失败!"); } } }控制台输出:
成功! 成功!我们可以看到,和我们预期的答案是一致的
Integer类默认自带了缓存,可能会导致某些情况下出现一些匪夷所思的结果,所以我们在使用的时候需要注意!
好了,今天我们就到这了,大家可以思考一个问题,Java中的8中基本数据类型都有对应的包装类,那么是不是所有的包装类内部都有缓存呢?欢迎大家下方留言!
欢迎关注小强1024实验室,和小强一起用技术改变世界