java里128有何魔力? 聊聊Integer的缓存
TL;DR Integer在-128到127范围内使用缓存,==比较可能违反直觉,始终用equals比较包装类
Java 的 Integer 缓存机制是一个高频面试题,也是日常开发中容易踩坑的地方。理解它,首先从一个看起来违反直觉的实验开始。
诡异的 128
1 | Integer a = 148; |
同一个 == 比较,148 返回 false,48 返回 true。原因就在于 Integer 缓存。
IntegerCache 源码分析
当 Java 编译 Integer a = 48 时,实际上执行的是:
1 | Integer a = Integer.valueOf(48); |
来看 Integer.valueOf() 的源码(JDK 8):
1 | public static Integer valueOf(int i) { |
核心逻辑:如果参数值在缓存范围内(默认 -128 ~ 127),直接从缓存数组中返回同一个对象;超出范围才 new Integer(i)。
这就是为什么 48 在缓存范围内所以 == 为 true,而 148 超出范围每次 new,所以 == 为 false。
IntegerCache 是一个私有的静态内部类:
1 | private static class IntegerCache { |
你可以通过 JVM 参数调整缓存上限:
1 | java -Djava.lang.Integer.IntegerCache.high=500 MyApp |
其他包装类的缓存
| 包装类 | 缓存范围 | 备注 |
|---|---|---|
Boolean |
TRUE / FALSE |
只有两个值 |
Byte |
-128 ~ 127 | 全部缓存 |
Short |
-128 ~ 127 | 同 Integer |
Long |
-128 ~ 127 | 同 Integer |
Character |
0 ~ 127 | ASCII 范围 |
Float |
无 | 浮点数缓存意义不大 |
Double |
无 | 同 Float |
三个常见踩坑场景
1. HashMap 的 Key
1 | Map<Integer, String> map = new HashMap<>(); |
HashMap 用 equals() 和 hashCode(),不受 == 影响。但如果你用了 IdentityHashMap,缓存边界就成了一个隐形的 bug 来源。
2. for 循环中的 Integer 比较
1 | // ❌ 写法 |
3. 锁对象
1 | // ❌ 危险!128 以下的值每次返回同一个对象,等于用的是同一个锁 |
为什么缓存范围是 -128 ~ 127?
这是一个字节的有符号表示范围。统计上,这个区间覆盖了日常编程中最常使用的整数值(循环计数器、数组索引、小常量等)。《Java Language Specification》§5.1.7 明确规定了这个行为——这不是实现细节,是有规范保障的。
最佳实践
- 比较 Integer 值时始终用
equals(),不要用!= - 能用
int的地方不要用Integer——基本类型没有缓存陷阱,性能也更好 - 永远不要用 Integer 做锁对象
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Mobility!
评论










