【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

返回结果:
【Java】从源码角度分析128陷阱_第1张图片

二、从源码角度解析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

你可能感兴趣的:(java,java,开发语言)