Integer变量的比较bug

Integer变量的比较bug

执行下例代码,会出现神奇现象:i_0 等于 i_1,但 i_2 不等于 i_3。明明都是一样的数值,前者为何相等,后者为何不等呢?

public class Main {
    public static void main(String[] args) {
        Integer i_0 = 100;
        Integer i_1 = 100;
        System.out.println(i_0 == i_1);
        Integer i_2 = 128;
        Integer i_3 = 128;
        System.out.println(i_2 == i_3);
    }
}

我们只知道Integerint型的装箱类型,但并不知Integer的庐山真面目。

Integer中有一个静态私有类IntegerCache,IntegerCache有一个属性cache[],这个属性被用来存储 -128~127 范围内的整数,不过这个范围的上限支持修改,设置JVM运行参数-Djava.lang.Integer.IntegerCache.high=

Integer.class源码

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;
        // 获取 java.lang.Integer.IntegerCache.high参数值(定义参数-Djava.lang.Integer.IntegerCache.high=2000,这样你的i_2==i_3就可以实现了)
        String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        /*
         * 没有设置过-Djava.lang.Integer.IntegerCache.high参数则为null——不进入if
         * 这一步的目的是将获取到cache[]的右极限
         * */ 
        if (integerCacheHighPropValue != null) {
            try {
                // string型转int型
                int i = parseInt(integerCacheHighPropValue);
                // 比较 设置值 和 127,取值大者
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                /**
                 * 比较 刚比较出来的最大值 和 0x7fffffff+128-1 比较,取最小者
                 * 为什么做这一步呢,不是多此一举吗?其实是为了预防传入值过大,超
                 * 出Integer所能表示的数值的最高限制
                 */
                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;// 为high赋值,默认赋值127
        
        // 重新定义cache的大小,127-(-128)+1 = 256【这是没有设置过-Djava.lang.Integer.IntegerCache.high参数的前提下】
        cache = new Integer[(high - low) + 1];
        int j = low;//low = -128
        // 依次向cache中填入数据(从-128开始)
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        // 断言high是大于等于127的,不过这段代码我是没有理解其用意
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

由上述的代码可以看出,Integer的cache[]的底线一直是-128,而其最大值是可以通过-Djava.lang.Integer.IntegerCache.high进行修改,修改了最大值,相对应的cache的大小也会发生变化。

了解了Integercache[],下面开始解释为何 i_2 不等于 i_3?

public static Integer valueOf(int i) {
    /**
     * 判断i是否处于low和high之间,如果处于他们之间,则不会new一个Integer新对象,
     * 而是把cache[]中的对象返回;只有超出[low,high]范围的数值才new一个新对象
     * 并返回。所以如果我们设置给JVM的参数java.lang.Integer.IntegerCache.high
     * 的值满足i_2 == i_3的范围,那么就可以让结果为true
     * */
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

cache[] 完整代码是:

static final Integer cache[];

这说明cache[]是保存在方法区的常量,一旦加载便不再被修改,仅能访问。

所以建议在比较装箱数据时使用.equals(obj)方法
如:i_2.equals(i_3)

posted @ 2024-04-28 14:40  勤匠  阅读(1)  评论(0编辑  收藏  举报