从源码解析Java中的“128陷阱”

从源码解析Java中的“128陷阱”

现象:为什么Integer(128) == Integer(128)返回false?

在Java中,以下代码会输出不同的结果:

Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true

Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false

这是因为Java对**-128到127之间的Integer对象**进行了缓存,导致范围内外的对象比较行为不同。这一现象被称为“128陷阱”。


源码解析:IntegerCache的实现

Java通过静态内部类IntegerCache实现缓存机制,核心源码如下(修正了用户提供的代码片段中的笔误): 在这里插入图片描述

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // 默认 high 值为127
        int h = 127;
        // 尝试通过系统属性配置上限
        String integerCacheHighPropValue = 
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = Integer.parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127); // 下限不能低于127
                // 上限不能超过Integer.MAX_VALUE - (-low) -1(防止溢出)
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch (NumberFormatException nfe) {
                // 配置无效时忽略
            }
        }
        high = h;

        // 初始化缓存数组
        cache = new Integer[(high - low) + 1];
        int j = low; // 修正变量名错误(原代码中误写为i++)
        for (int k = 0; k < cache.length; k++) {
            cache[k] = new Integer(j++);
        }

        // 断言:缓存上限至少为127
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

关键逻辑分析

  1. 缓存范围

    • 默认范围是-128127,但可通过JVM参数-Djava.lang.Integer.IntegerCache.high=xxx扩展上限。
    • 上限最大值受Integer.MAX_VALUE - (-low) -1限制,防止数组长度溢出。
  2. 缓存初始化

    • 在类加载时,静态块会创建并填充缓存数组。
    • 若配置了自定义上限,会优先使用,但不会低于127。
  3. 自动装箱与缓存

    • 当使用Integer.valueOf(int)或自动装箱(如Integer a = 127;)时,会直接从缓存中获取对象。
    • 源码片段
      public static Integer valueOf(int i) {
          if (i >= IntegerCache.low && i <= IntegerCache.high)
              return IntegerCache.cache[i + (-IntegerCache.low)];
          return new Integer(i);
      }
      

为什么会产生“128陷阱”?

  • 缓存范围内valueOf返回的是同一个缓存对象,==比较的是对象内存地址,结果为true
  • 缓存范围外:每次valueOf会创建新对象,==比较的是不同对象的内存地址,结果为false

如何避免?

  1. 使用equals()代替==
    equals()比较的是整数值,而非对象地址。
  2. 使用基本类型int
    直接使用int可绕过对象比较问题。
  3. 谨慎配置缓存上限
    修改上限需权衡内存开销,不建议盲目扩大。

总结

“128陷阱”本质是Java对常用小整数的优化策略。理解IntegerCache的实现后,开发者应始终使用equals()比较包装类型对象,或在需要高性能的场景下优先使用基本类型。源码中通过灵活的配置和断言机制,既保证了默认性能,又提供了扩展性,体现了Java设计的巧妙之处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值