自动装箱 / 拆箱与IntegerCache缓存机制
public class Main { public static void main(String[] args) { int a = 10; int b = 10; Integer a1 = 10; Integer b1 = 10; Integer a2 = new Integer(10); Integer b2 = new Integer(10); System.out.println(a==b); // true 基本数据类型 System.out.println(a1==b1); // T -128~127 缓存 System.out.println(a2==b2); // F System.out.println(a1 == a); // T 自动拆箱 System.out.println(a1.equals(a));// T 自动拆箱 System.out.println(a1 == a2); // F System.out.println(a == a2); // T 自动拆箱 } }一、代码逐行结果与原理表
| 代码 | 结果 | 核心知识点 |
|---|---|---|
int a = 10; int b = 10; | - | int是基本数据类型,变量直接存储数值本身 |
Integer a1 = 10; Integer b1 = 10; | - | Integer是包装类,这里发生了自动装箱;IntegerCache缓存-128~127的对象 |
Integer a2 = new Integer(10); | - | new Integer()会在堆中创建全新对象,不使用缓存 |
a == b | true | 基本类型==直接比较数值本身,10 == 10 |
a1 == b1 | true | 两个Integer都来自缓存池,指向同一个对象,地址相同 |
a2 == b2 | false | 两个new Integer()是不同堆对象,地址不同,==比较的是地址 |
a1 == a | true | 包装类与基本类型用==比较时,包装类自动拆箱为int,再比较数值 |
a1.equals(a) | true | Integer.equals()会自动装箱a为Integer,然后比较数值本身 |
a1 == a2 | false | 两个不同来源的Integer对象,地址不同,==比较地址 |
a == a2 | true | a2自动拆箱为int,和a比较数值,10 == 10 |
二、核心知识点拆解
1. 基本数据类型 vs 包装类
- 基本类型(
int):直接存储数值,==比较的是值 - 包装类(
Integer):存储在堆中,是对象;==默认比较内存地址,只有equals()才比较数值
2. 自动装箱与自动拆箱
- 自动装箱:
Integer a1 = 10;→ 编译器自动调用Integer.valueOf(10),把int包装成Integer对象 - 自动拆箱:
a1 == a→ 编译器自动调用a1.intValue(),把Integer拆成int,再比较数值 - 触发场景:包装类和基本类型用
==、+等运算符比较 / 运算时,会自动拆箱
3.IntegerCache缓存池
- 缓存范围:默认
-128 ~ 127(可通过 JVM 参数修改上限) - 作用:减少频繁创建小整数对象的开销
- 规则:
Integer.valueOf(10)会直接返回缓存中的对象,所以a1 == b1为truenew Integer(10)会强制创建新对象,不走缓存,所以a2 == b2为false
4.==和equals()的区别
| 场景 | == | equals() |
|---|---|---|
两个int | 比较数值 | 不存在(基本类型无方法) |
两个Integer | 比较内存地址 | 比较包装的数值(Integer重写了equals) |
int和Integer | 触发自动拆箱,比较数值 | 触发自动装箱,比较数值 |
三、易错点
- 判断
Integer数值是否相等,永远用equals(),不要用==因为超过缓存范围(比如128)的Integer对象,即使数值相同,==也会返回false。 new Integer()永远不走缓存,哪怕数值在-128~127之间,也是新对象。- 包装类和基本类型比较时,会自动拆箱,此时
==也能得到正确的数值比较结果,但代码可读性差,不推荐。
