IntegerCache使用的问题与源码解读
1、使用中的代码演示
class IntegerTest {

    public static void main(String[] args) {
        Integer a = 88;
        Integer b = new Integer(88);
        Integer c = Integer.valueOf(88);
        System.out.println(a == b);
        System.out.println(a == c);
        System.out.println(a.equals(b));
        System.out.println(a.equals(c));
    }

}

执行结果如下

false
true
true
true

我们知道Integerequals方法是通过intValue值进行判断,a.equals(b)a.equals(c)结果均为true没有异议,但其中为什么a==ba==c的结果不一致呢?

2、原因分析

等号==是进行对象的比较,从结果说明a与c为同一个对象,b为不同的一个对象,可以通过debug调试代码得到验证,定义Integer a = 88;Integer c = Integer.valueOf(88);的对象为同一个。

image.png

继续调试以下代码观察

    public static void main(String[] args) {
        Integer a = 88;
        Integer b = 88;
        Integer c = 88;
        Integer d = 188;
        Integer e = 188;
        Integer f = 188;
        System.out.println();
    }

可以发现a、b、c的对象为同一个,而d、e、f的对象则不是同一个。 image.png

3、源码解读(jdk8)

是什么原因造成这样的结果呢?我们看一下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);
    }

这段代码意思就是判断传入值是否在缓存的区间范围内,可以理解为判断是否为热点数据,如果是直接返回缓存对象,否则new一个对象返回。

再继续看类IntegerCache源码,看看lowhigh这两个区间值是如何定义

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

从源码中我们可以看到low为-128是个固定值,而high的值默认为127但却可以通过参数的方式配置java.lang.Integer.IntegerCache.high,按这个逻辑我们把high配置到大于188的话,对象就会是同一个了,需注意high的最大取值。

源码中可以找到配置high的参数可以通过属性参数或jvm参数完成配置,即-Djava.lang.Integer.IntegerCache.high=189-XX:AutoBoxCacheMax=189

4、实践总结

idea中设置属性参数或jvm参数调试代码,可以看到设置high参数后d、e、f也为同一个对象了 image.png

通过一个整型对象的大小比较引申出系列问题的探讨以及思考,其实在IntegerCache类中我们还可以看到为什么只允许设置上限high呢?下限low为什么不能同样设置呢?是基于什么样的考虑呢?有官方的 issue,简单回复没有必要


赞赏(Donation)
微信(Wechat Pay)

donation-wechatpay