关于Java包装类中的“128陷阱”

一、问题引入

        我们在日常学习和工作中,可能听说过“128陷阱”,那么什么是“128陷阱”呢?这里要先提到java中的一个基本类型int以及int所对应的包装类Integer

        那么大家可以思考下面这段代码会输出什么值呢?

        int n = 128;
        int n1 = 128;
        int m = 127;
        Integer m1 = 127;
        int e = 128;
        Integer e1 = 128;
        Integer d = 127;
        Integer d1 = 127;
        Integer f = 128;
        Integer f1 = 128;
        Integer g = 129;
        Integer g1 = 129;
        System.out.println("n==n1:"+(n==n1));
        System.out.println("m==m1:"+(m==m1));
        System.out.println("d==d1:"+(d==d1));
        System.out.println("e==e1:"+(e==e1));
        System.out.println("f==f1:"+(f==f1));
        System.out.println("g==g1:"+(g==g1));

下面是输出结果

n==n1:true
m==m1:true
d==d1:true
e==e1:true

f==f1:false
g==g1:false

那么输出结果和你期待的是一样的吗?如果不相同那我们接下来需要考虑为什么会出现这样的结果呢?

上面的问题总共分为4组:

  1. int n = 128;和int n1 = 128;
    这一组数据之间的比较就很简单了,就是基本数据类型间的比较,显而易见是相等的。
    
  2. int m = 127;和Integer m1 = 127;

    这一组数据之间的比较涉及了自动拆箱,什么是自动拆包呢?

    其实非常简单,就是说Integer类型的m1在和m进行比较时,会使用m1.intValue()自动转化成int类型,之后也就是简单的值与值之间的比较了。

  3. int e = 128;和Integer e1 = 128;
  4. 剩下三组放一起看
        Integer d = 127;
        Integer d1 = 127;
        Integer f = 128;
        Integer f1 = 128;
        Integer g = 129;
        Integer g1 = 129;

        这些数据均是Integer类型,照理来说,这些数据之间的比较应该相同才是,即:三组结果同为false或同为true。可是结果却不是这样

e==e1:true

f==f1:false
g==g1:false

如果大家验证可以发现Integer类型在值为128时发生,两个同为128的Integer类型对象,之间的比较开始变为false,也就是说128是true和false之间的临界值,这种现象被称为“128陷阱”。

二、探究原因

       1.“128陷阱”产生原因

         我想现在大家都比较好奇,“128”陷阱是怎么产生的呢?,除了128以外,是否还有其他临界值呢?接下来,让我们进入源码,来探究“128陷阱”是怎么发生的

        首先我们需要了解Integer a = 10是怎么创建的,简单来说这件事情就四个字,自动装箱,没错就是和自动拆箱对应的。仔细讲一下的话就是

Integer a = 10

相当于

Integer a = Integer.valueOf(10)

        想必聪明的你已经猜到了,“128陷阱”就是发生在,Integer.valueOf(10)中的

        2.进入Integer.ValueOf()函数

        源码:

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

        这里可以看到,当形参i的值处于区间[IntegerCache.low,IntegerCache.high]之间的时候,方法会直接返回一个Integer数组中的元素

(也就是IntegerCache.cache[i + (-IntegerCache.low)]),所以只要i的值在区间内,那么他们返回的对象就是同一个(对象地址也相同),只有在i不在区间内的时候,该方法才会使用构造方法new Integer(i)返回一个新的对象,这个时候即使i值相同其生成的对象地址也就不相同了,所以此时比较返回值将是false;

        3.IntegerCache.low,IntegerCache.high和数组IntegerCache.cache

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

        static {
            // high value may be configured by property
            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);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

IntegerCache.low,IntegerCache.high和数组IntegerCache.cache的值都是在这代代码中定义的

具体来说就是

static final int low = -128;
static final int high;
int h = 127;
high = h;
cache = new Integer[(high - low) + 1];

这几段代码定义的

所以如果我们赋值的数i在[-128,127]之间,他就会返回cache[i - (-128)]中已经创建好的对应Integer对象。如果不在之间,就会返回一个新new的Integer对象。

三、总结

        我们在学习工作不仅要清楚一件事情或者工具该怎么使用,更要清楚在使用工具的过程中,java是怎么实现的,内部具体发生的事情,是怎么发生的。只有这样才能够越学越清楚,才能真正的融会贯通。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值