【Java】从源码角度分析128陷阱

一、从概念了解128陷阱

在 Java 中,整型包装类 java.lang.Integer 存在一个 “128 陷阱”,具体指的是在范围为 -128 到 127 之间的整数值(包括 -128 和 127),在自动装箱(Autoboxing)时会被缓存,而超出这个范围的整数值则不会被缓存。这是由于 Integer 类在内部使用了一个缓存池(Cache),目的是为了提高性能和节省内存。( Java拆箱装箱
当使用自动装箱或 Integer.valueOf() 方法将一个整数赋值给 Integer 类型的变量时,如果这个整数值在 -128 到 127 之间,将直接从缓存池中获取 Integer 对象,而不会创建新的对象。这样做的好处是可以重用已有的对象,减少了对象的创建和销毁开销。然而这种缓存机制可能导致128陷阱。
由于-128到127的整数数值是被缓存的,当你比较两个处于这个范围内的‘ Integer ’对象时,使用‘==’运算符时会返回true,因为他们引用的同一个缓存对象
代码示例:

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

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

返回结果:
示例代码运行结果

二、从源码角度解析128陷阱

深入了解 java.lang.Integer 类中的实现细节。在 Java 中,整型包装类 Integer 是一个 final 类,它表示一个 32 位带符号的二进制补码整数。
Integer 类在内部使用了一个静态数组 IntegerCache,用于缓存范围在 -128 到 127 之间的 Integer 对象。这个缓存池的初始化默认大小是 -128 到 127,可以通过 JVM 参数java.lang.Integer
.IntegerCache.high 来调整上限。

打开Integer类可以看到相关代码:

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];
    static {
        // 调用 Integer.getInteger("java.lang.Integer.IntegerCache.high") 方法获取上限值
        int h = 127;
        String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // 使用 JVM 参数中的值来设置缓存上限
                h = Math.min(i, Integer.MAX_VALUE - (-low) - 1);
            } catch( NumberFormatException nfe) {
                // 如果解析 JVM 参数失败,则使用默认的 127
                // 同时也说明了 IntegerCache.high 参数是非公开的,不能直接通过代码设置
            }
        }
        high = h;
        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
        // 缓存数组被创建并初始化了 -128 到 127 范围内的 Integer 对象
        // 超过此范围的整数值不会被缓存
    }
    private IntegerCache() {}
}

根据源码可以看到,如果使用自动装箱或者‘Integer.valueOf()’方法将一个整数类赋值给‘Integer’类型的变量时,如果整数值在-128-127之间,将直接从缓存池中获取对应的’Integer’对象里,如果超过了这个范围,将会重新创建一个新的’Integer’对象,而不是从缓存池中获取。

总结

“128 陷阱” 的原因:当整数值超过了 -128 到 127 范围时,两个不同的整数值被装箱后得到的 Integer 对象不再是同一个缓存对象,因此在使用 == 运算符比较时,会返回 false。而在范围内的整数值会从缓存池中获取,因此它们引用的是同一个缓存对象,使用 == 运算符比较时会返回 true。

如果想比较’Integer’对象,怎么做

使用equals()方法来比较Integer对象的值。具体参考友情链接,==与equals的区别

友情链接

【Java】==和 equals() 的区别:http://t.csdn.cn/Vtf42
【Java】拆箱和装箱(附示例代码讲解):http://t.csdn.cn/cS4bD

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

去码头整点薯条​⁢⁢⁢⁡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值