1039 字
约 3 分钟
6
S04-B02 · 基本类型与装箱:`==` 什么时候会骗你

适用读者:被 Integer 比较坑过的人。
前置:S04-B01。
实测环境:OpenJDK 21.0.12.1(2026-11-05)。
覆盖旧文:A-1698(265) A-1704(79) A-1762(136) A-1692(85) A-1760(263) A-1780(55) A-811(72) + 时间 API 4 张(59) = 1,014 点。
覆盖扩展:E-S04-003(Integer 缓存)、E-S04-004(值传递)。
上一篇:S04-B01 · Java 的定位、版本与"一次编写"到底怎么实现
下一篇:S04-B03 · 流程控制与运算符。


1. 一句话结论

== 比较的是"值"还是"引用",取决于两边是不是基本类型;而装箱让"看起来是值比较"的代码实际上在比较引用——这就是 127 与 128 的差别来源。

实测(JDK 21):

127==127: true
128==128: false
1000==1000: false
new Integer(127)==127: true
new==new(127): false  equals: true

2. 为什么 127 相等、128 不相等(E-S04-003)

原因:Integer.valueOf(int) 有一个缓存(默认 −128..127,可通过 -XX:AutoBoxCacheMax 扩大)。缓存范围内返回同一个对象,范围外 new 一个新对象。

表达式 编译后 结果
Integer i = 127 Integer.valueOf(127) → 缓存对象 同一对象 → == true
Integer i = 128 Integer.valueOf(128) → 新对象 不同对象 → == false
new Integer(127) 强制新建(已废弃,见下) 不同对象 → == false

new Integer(...) 在 JDK 9 起标记废弃、后续版本标记移除(实测编译时有 warning)。生产代码不要用,让编译器走 valueOf。


3. 四种比较,一张表说清

比较 比的是什么 建议
int == int 数值 ✅
Integer == Integer 引用(缓存范围内可能"碰巧"相等) ❌ 用 equals
Integer == int 拆箱后比数值 ⚠️ 有 NPE 风险(Integer 为 null 时)
Integer.equals(Integer) 数值 ✅ 推荐

实测补充:

new Integer(127)==127: true      ← 右侧拆箱,比数值
new==new(127): false  equals: true

注意 ==127 那种写法:右侧是 int,左侧 Integer 会自动拆箱——如果左侧是 null,直接 NullPointerException。这是 == 最危险的用法。


4. 值传递(E-S04-004)

Java 只有值传递:基本类型传值,对象传"引用的值"(引用的副本)。

void modify(int x) { x = 99; }              // 不影响调用方
void modify(int[] a) { a[0] = 99; }         // 影响(改的是同一个数组对象)
void reassign(int[] a) { a = new int[]{9}; } // 不影响(改的是副本引用)
操作 是否影响调用方
改基本类型形参 ❌
改对象内部状态 ✅
让形参指向新对象 ❌

判据:"我改的是对象,还是引用本身?"


5. 字符串:常量池与 ==(预告 B08)

实测:

s1==s2: true            // 字面量 → 常量池同一对象
s1==s3: false           // new String → 堆上新对象
s1.equals(s3): true
常量折叠 s4==s1: true    // "a"+"b"+"c" 编译期折叠

结论:字符串比较一律用 equals;== 只在你明确想比较"是否同一个对象"时用(几乎从不需要)。


6. 五个误区

误区 真相
"Integer == Integer 比较数值" 比较引用(缓存范围内可能碰巧相等)
"127 与 128 是玄学" 是 valueOf 缓存 −128..127
"可以用 new Integer()" 已废弃/标记移除
"Java 有引用传递" 只有值传递(对象传引用的副本)
"== null 与 equals(null) 等价" equals(null) 返回 false;== null 判断是否空引用

7. 自检

  1. 为什么 Integer a=127,b=127 时 a==b,而 128 时不等?
  2. Integer x = null; if (x == 1) 会发生什么?
  3. modify(int[] a) 与 reassign(int[] a) 的差别?
  4. new String("abc") == "abc" 为什么 false?
  5. 什么时候可以安全用 == 比较对象?

8. 下一篇

S04-B03 · 流程控制与运算符

类型讲完,下一篇过一遍控制流——以及 Java 里几个容易踩的运算符细节(++、短路、位运算)。


本篇属于系列《S04 · Java 语言核心》。旧文来源:A-1698/1704/1762/1692/1760/1780/811;扩展点 E-S04-003/004。所有输出为 OpenJDK 21 实测。

S04-B02 · 基本类型与装箱:`==` 什么时候会骗你
https://www.clxhxhhr.top/posts/5217/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。