浅谈Java128陷阱

在对两个Integer类型的对象用==判断是否相等时发现了一点问题,代码如下:

        Integer temp1 = 100;
		Integer temp2 = 100;
		Integer temp3 = 200;
		Integer temp4 = 200;
		System.out.println("temp1==temp2:");
		System.out.println(temp1==temp2);
		System.out.println("temp3==temp4:");
		System.out.println(temp3==temp4);

 运行结果如下:


一、问题产生原因

        在两个值相等的Integer类型的对象使用==进行比较的时候,预期结果应该是返回为true,但一组返回了true,另一组返回了false。

二、理论分析

        预期结果的依据是值相等,这其实是错误的。

        如果是基本数据类型,可以通过==来进行值相等的判断。

        不过本次使用的是包装类Integer来进行比较的,对比的不止值是否相等,还有这两个对象的地址是否相等。

        这也就是为什么第二组数据输出的结果为false。

        这也就引出了一个新的问题,同样是Integer包装类型的第一组数据为什么会返回true?这里就需要从源码的角度来解析一下了。

三、源码分析

1.自动拆箱

        在分析源码之前要知道我们要找的源码来源于哪,为什么要找这块的代码。

        这次的问题是要从初始化的时候开始分析的。

        在上面的示例中我们用Integer定义的数其实是简写形式,正确的写法:(也就是自动装箱,这里不多进行阐述)

Integer temp1 = Integer.valueOf(100);

        其他的几个数据也是一样的。这样我们就会发现,我们在最开始初始化的时候就调用了一个Integer包装类中的valueOf(int a)方法。这样我们就找到了需要去分析的部分,然后按住Ctrl用鼠标左键点击该方法就可以跳转到源码。

2.分析源码

        下面就是valueOf()方法的源码,从源码中我们可以发现,这个方法对初始化时传入的int类型参数进行了一次判断,里面出现了一个 IntegerCache 类,并访问了它的三个常量。那我们的下一个目标就是先去这个类中分析一下具体有什么东西。

   下面的是 IntegerCache 类的源码,里面的东西很多,但我们需要的其实只有其中的常量 low , high 和 cache[ ]。 low 的值直接给出为 -128,high 的值经过 static 中代码的执行后赋值,得到 high 的值为 127。cache[ ] 最后的取值为  -128 ~ 127。

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() {}
    }

        这时我们再返回第一部分的源码分析,就会发现其判断区间为 -128 ~ 127。如果我们初始化时参数的值在这个区间,那么就会直接返回常量 cache 中的值等于该值的那个 Integer 类型的对象。这也就是为什么第一组数据返回的结果为true,因为这两个对象指向的其实都是 cache 中的同一个地址。而这个区间外的值则会开辟一个新的地址空间去存储,因此第二组的两个对象指向的地址一定是不同的,结果为false。


总结

        这是我第一次尝试通过源码的方式来解决问题,过程可能会有很多不足,但也打开了一个新的方向,希望对大家有所帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值