Java 自动装箱 自动拆箱

为什么会写这篇文章? 因为在比较两个ArrayList<Integer>元素的值是否完全对应相等时, 遇到了一个大坑

image-20220304153459943

明明都是-685, 怎么就不相等了呢? 起初猜想是因为Integer比较的是地址, 但5判断的是相等啊, 又经过一番搜索, 才明白, 遂写下以记录

自动装箱 自动拆箱于JDK1.5中引入

int常量池

要搞清楚上面这个问题, 就要了解常量池

JVM会自动维护八种基本类型的常量池,int常量池中初始化-128~127的范围

我们来看一下Integer.java的源码来验证一下

image-20220304155025669

JVM在启动时就已经将-128~127的Integer对象全部new出来, 因为这个范围内的数比较常用

自动装箱

定义: 自动将基本数据类型转换为封装类型(如int转为Integer)

1
2
// 自动装箱
Integer a = 5; // 相当于Java编译器替我们执行了 Integer.valueOf(5);

可以通过反编译class文件看出

image-20220304155437062

valueOf方法会判断数值在不在-128~127范围内, 在的话直接返回已经创建的Integer对象, 不在的话再new出来. 这也就解释了为什么最开始的问题中5是相等的, 而-685不相等

自动拆箱

定义: 自动将封装数据类型转换为基本类型(如Integer转为int)

1
2
3
4
// 自动装箱
1. Integer a = 5;
// 自动拆箱
2. int b = a; // 相当于Java编译器替我们执行了Integer.intValue(5);

image-20220304161943395

总结

最开始的问题中5相等, 是因为两个ArrayList<Integer>的值都是通过add(int i)添加的, 换句话说, 都发生了自动装箱, 调用了valueOf方法. 5在常量池中, 所以直接返回, 两个list中5相等

而-685不在常量池中, 都是在堆内存中new出来的, 地址不相等

当然如果Integer a = new Integer(5);, Integer b = new Integer(5);, a==b为false, 因为此过程是直接new, 不会发生自动装箱, 也就不会调用valueOf方法