Java中Long自动装箱通过编译器调用valueOf()实现,配合-128~127范围的LongCache缓存复用对象;超出该范围或使用new、parseLong等则不走缓存;故==比较仅在缓存范围内可靠,推荐用equals()。

自动装箱本质是编译器帮你调用 valueOf()
当你写 Long l = 100L;,编译器实际生成的是:Long l = Long.valueOf(100L);
不是 new Long(100L)(后者已废弃)。
同理,拆箱如 long n = l;,等价于 long n = l.longValue();。
这意味着:是否走缓存,完全取决于你用的是 valueOf() 还是构造器(或 parseLong())。
LongCache 是静态预加载的固定数组
Long 内部用一个静态内部类 LongCache 实现缓存池:
- 缓存范围固定为 -128 到 127(含),共 256 个
Long实例; - 数组
cache[]在Long类首次被加载时就初始化完成; - 索引计算方式为
(int)l + 128,例如l = 0→ 索引 128,l = -128→ 索引 0; -
valueOf()方法先判断值是否在 [-128, 127] 区间,是则返回缓存对象,否则新建实例。
缓存只对 valueOf() 和自动装箱生效
以下行为不会命中缓存:
-
new Long(100):直接 new,绕过缓存(且该构造器自 Java 9 起已标记为 deprecated); -
Long.parseLong("100"):返回基本类型long,不产生对象; -
Long.valueOf("100"):会先解析再装箱,但字符串解析后仍调用valueOf(long),所以只要结果在范围内,仍走缓存; - 超出 -128~127 的值,比如
Long.valueOf(1000),每次都会创建新对象。
== 比较失效的根本原因在这里
因为缓存只覆盖小范围数值,所以:Long a = 100L, b = 100L; → a == b 为 true(同一缓存对象);Long c = 200L, d = 200L; → c == d 为 false(两个不同对象);
而 Objects.equals(c, d) 或 c.equals(d) 始终安全,因为重写了 equals() 比较数值本身。


















