java中integer缓存池是享元模式的典型应用:通过预缓存-128~127范围内的integer对象实现共享复用,valueof()为工厂方法,new integer()绕过缓存;该范围权衡内存开销与命中率,且仅对valueof及自动装箱生效。

Integer 缓存池就是享元模式的典型落地
Java 的 Integer 在 -128 ~ 127 范围内复用对象,不是巧合,而是标准享元(Flyweight)模式的实践:用少量共享对象支撑大量逻辑请求,避免重复创建。它不叫“享元类”,但行为完全符合——内部状态固定(数值不可变),外部无依赖,可安全共享。
为什么选 -128 到 127 这个范围?
这不是拍脑袋定的,是享元模式中“权衡共享收益与内存成本”的直接体现:
-
IntegerCache初始化时就预分配cache数组,长度固定为 256(-128 到 127 共 256 个值),内存开销极小(几十 KB) - 下限 -128 对齐
byte最小值,覆盖常见负数场景(如 HTTP 状态码、错误码) - 上限 127 覆盖绝大多数循环索引、数组长度、HTTP 状态码(4xx/5xx)、枚举序号等高频值
- 若扩大到 1000,缓存对象增为 1129 个,内存占用翻几倍,但命中率提升有限——享元失效
valueOf() 是享元工厂方法,new Integer() 绕过享元
Integer.valueOf(int) 就是标准的享元工厂:查缓存、命中则返回,未命中才新建。而 new Integer(int) 强制走构造路径,彻底跳过缓存逻辑——这就像手动 new 一个 String 而不用字符串常量池。
-
Integer a = 100;→ 编译为Integer.valueOf(100)→ 命中缓存 → 同一对象 -
Integer b = new Integer(100);→ 强制堆上新建 → 地址不同 →a == b为false -
Integer c = 200;→valueOf(200)超出缓存范围 → 新建对象 →c == Integer.valueOf(200)仍为false
Long 和 Boolean 的缓存策略差异暴露享元设计意图
享元是否启用、范围是否可调,取决于该类型在实际使用中的“共享价值”:
-
Boolean只有TRUE/FALSE两个实例 → 全量缓存,且不可配置 → 共享收益 100%,成本趋近于 0 -
Long在 JDK 源码中保留了LongCache结构,但默认未启用(cache数组为空)→ 高位长整数复用率低,享元性价比差 -
Integer是唯一默认开启、范围可调(-XX:AutoBoxCacheMax=)、且被语言规范强制要求实现的享元 → 它是 JVM 层面公认的“高价值共享候选”
真正容易被忽略的是:缓存行为只作用于 valueOf() 及其触发的自动装箱;任何显式 new、反射构造、或反序列化产生的 Integer 都不参与享元。别假设“值一样就一定共享”。










