Integer 的比较分为三种情况,你需要根据场景选择正确的方法:

- 比较
Integer对象的值是否相等 (最常用) - 比较
Integer对象的引用(内存地址)是否相同 (很少用,但有特殊场景) - 比较
int基本类型的值是否相等 (最直接)
核心概念:Integer 的装箱与拆箱
在深入比较之前,必须理解 Integer 和 int 的区别。
int: 是 Java 的基本数据类型,它直接存储值,没有额外开销,存放在栈中。Integer: 是int对应的包装类,它是一个对象,包含一个int类型的字段,对象存放在堆中。
Integer 对象的创建过程涉及装箱,将 int 转换为 Integer 对象,而将 Integer 对象转回 int 的过程称为拆箱。
// 装箱: int -> Integer Integer a = 10; // 编译器会自动执行 Integer.valueOf(10) // 拆箱: Integer -> int int b = a; // 编译器会自动执行 a.intValue()
Integer 对象的比较之所以复杂,主要因为它是一个对象,而对象比较默认是比较内存地址。
比较 Integer 对象的值是否相等 (最常用)
这是绝大多数情况下你想要做的事情,你需要判断两个 Integer 对象内部的 int 值是否相同。

✅ 正确方法:使用 .equals()
Integer 类重写了 Object 类的 equals() 方法,它的作用就是比较两个 Integer 对象的值是否相等,而不是它们的内存地址。
示例代码:
Integer num1 = new Integer(10);
Integer num2 = new Integer(10);
// 使用 equals() 比较值
System.out.println("num1.equals(num2): " + num1.equals(num2)); // 输出: true
// 也可以使用 Objects.equals() (更安全,能处理null)
System.out.println("Objects.equals(num1, num2): " + Objects.equals(num1, num2)); // 输出: true
为什么不能直接用 ?
在比较对象时,比较的是它们的内存地址(引用)。new Integer(10) 会为 num1 和 num2 在堆中创建两个不同的对象,它们的内存地址不同,num1 == num2 为 false。
Integer num1 = new Integer(10);
Integer num2 = new Integer(10);
System.out.println("num1 == num2: " + (num1 == num2)); // 输出: false
比较 Integer 对象的引用是否相同
这种情况非常罕见,通常只在需要判断两个变量是否指向同一个对象实例时使用。

✅ 正确方法:使用
运算符用于比较两个对象的引用(内存地址),如果两个引用指向堆中的同一个 Integer 对象,则返回 true。
示例代码:
Integer a = new Integer(10);
Integer b = a; // b 指向 a 所指向的对象
System.out.println("a == b: " + (a == b)); // 输出: true,因为它们是同一个对象
Integer c = new Integer(10);
System.out.println("a == c: " + (a == c)); // 输出: false,因为它们是两个不同的对象
比较 int 基本类型的值是否相等
当你确定要比较的是两个基本类型 int 的值时,直接使用 即可,这是最简单、最高效的方式。
✅ 正确方法:使用
示例代码:
int x = 10;
int y = 10;
System.out.println("x == y: " + (x == y)); // 输出: true
// 当 Integer 对象被拆箱后,比较的是其基本类型的值
Integer z = 10;
System.out.println("x == z: " + (x == z)); // 输出: true,因为 z 被自动拆箱为 int 10
Integer 缓存带来的“陷阱”: 在特定情况下的“意外”成功
这是 Integer 比较中最容易让人困惑的地方,为了提高性能和减少内存占用,Integer 类提供了一个内部缓存(也称为“常量池”),范围在 -128 到 127 之间。
当你使用 Integer i = value; 这种方式(而不是 new Integer(value))创建 Integer 对象时,value 在 [-128, 127] 范围内,Java 不会创建新对象,而是直接从缓存中返回已经存在的对象。
示例代码:
// 在 [-128, 127] 范围内
Integer i1 = 127;
Integer i2 = 127;
// 因为 127 在缓存范围内,i1 和 i2 指向缓存中的同一个对象
System.out.println("i1 == i2 (127): " + (i1 == i2)); // 输出: true
Integer i3 = 128;
Integer i4 = 128;
// 因为 128 超出缓存范围,i3 和 i4 是两个新创建的对象
System.out.println("i3 == i4 (128): " + (i3 == i4)); // 输出: false
这个陷阱的总结:
new Integer(): 总是创建新对象, 比较永远为false(值相同的情况下)。Integer.valueOf(): 编译器会将Integer a = 10;转换为Integer.valueOf(10)。- 如果值在
[-128, 127], 比较可能为true(因为指向缓存)。 - 如果值超出范围, 比较为
false(因为创建了新对象)。
- 如果值在
Integer.parseInt(): 返回的是int基本类型,后续比较 是比较基本类型值。
| 你的目标 | 推荐方法 | 示例 | 原因 |
|---|---|---|---|
比较两个 Integer 对象的值 |
使用 equals() |
a.equals(b) 或 Objects.equals(a, b) |
这是 Integer 类设计的正确意图,不受缓存影响,能准确比较值。 |
比较一个 Integer 和一个 int |
使用 | int a = 10; Integer b = 10; a == b; |
会发生自动拆箱,比较的是两个基本类型的值,高效且正确。 |
比较两个 int 基本类型 |
使用 | int a = 10; int b = 10; a == b; |
最直接、最高效的比较方式。 |
| 判断两个变量是否指向同一个对象 | 使用 | a == b |
这是 的原始行为,用于比较引用地址。 |
一张图看懂
graph TD
A[开始比较 Integer] --> B{你的目的是什么?};
B -- 比较值是否相等 --> C[使用 .equals() 或 Objects.equals()];
B -- 比较是否是同一个对象 --> D[使用 ==];
B -- 其中一个是基本类型 int --> E[使用 == (会自动拆箱)];
C --> F[结果是 true/false (基于值)];
D --> G[结果是 true/false (基于内存地址)];
E --> H[结果是 true/false (基于拆箱后的值)];
subgraph "重要提醒"
I[Integer 有-128到127的缓存<br>可能导致 == 比较值时出现意外结果]
end
面试高频问题
问题: 以下代码的输出结果是什么?为什么?
Integer a = 100; Integer b = 100; Integer c = 200; Integer d = 200; System.out.println(a == b); // ? System.out.println(c == d); // ?
答案:
System.out.println(a == b);输出true。- 原因:
100在Integer的缓存范围[-128, 127]内。a和b都是通过Integer.valueOf(100)创建的,它们指向缓存中的同一个Integer对象, 比较引用地址为true。
- 原因:
System.out.println(c == d);输出false。- 原因:
200超出了缓存范围。c和d都是通过Integer.valueOf(200)创建的,但由于值不在缓存中,JVM 会为它们分别创建两个新的Integer对象,这两个对象在堆中的内存地址不同, 比较引用地址为false。
- 原因:
补充问题: 如果要比较 c 和 d 的值,应该怎么写?
答案: System.out.println(c.equals(d));,这会输出 true。
