IntegerCache

释放双眼,带上耳机,听听看~!

面试题:问以下代码输出的结果是多少?

public class IntegerTest {

    @Test
    public void test() {
        Integer a = 127;
        Integer b = 127;
        System.out.println(String.format("运行结果:%s", a == b));
        a = 128;
        b = 128;
        System.out.println(String.format("运行结果:%s", a == b));
    }

}

如果不仔细看上面的代码,那么我想很多人都会很快的说出运行的结果。但如果仔细查看代码,却不知道上述代码中的要考察的相关知识时,我想也不一定能准确说出正确的运行结果。那么下面我们看一下上述代码的运行结果:

运行结果:true
运行结果:false

你猜对了吗?为什么上面的代码显示的结果居然是不一样的呢?下面我们详细分析一下上述代码主要考察的知识点。


上述代码主要考察的是Java中Integer包装类对象的知识。但在这里有一个很隐性的知识点,也就IntegerCache对象。也就是因为这个对象的存在才导致上述代码中运行的结果不一致的。下面我们来了解一下Java中IntegerCache对象的知识。


IntegerCache

IntegerCache类实际上是Java中Integer中的缓存类,目的是节省内存消耗,提高程序性能。因为我们知道,在Java中每创建一个对象,都会将对象存储在堆内存中。而当堆内存中的对象存储非常多时,就有可能造成内存泄漏。而在我们日常的项目开发中我们使有用Integer类型的频率非常高。使用频率高创建对象也就越多,堆内存中的对象也就越多,所以也就会可能发生上述中的内存溢出等问题。所以Java为了解决上述问题。于是设计了IntegerCache类,看名字就知道IntegerCache是个缓存类,既然是缓存类,目的就是可以将相关的数据缓存下来,这里的数据指的就是Integer类的值。也就是上述代码中的等于右边的数值。那既然IntegerCache类可以缓存数字,为什么上述代码中的结果不一样呢?这个原因就是IntegerCache类有一个缓存范围。IntegerCache类缓存的数据范围为是-128到127之间。所以上述代码中前两行代码中输出结果为true(127在IntegerCache类缓存的数据范围内,于是将127缓存起来,当程序在使用这个127数字时,因为缓存中已经有了,于是直接使用缓存中的127,所以结果为true),而后二行代码输出的结果为false(超出IntegerCache类的缓存范围,于是不能缓存,所以创建了新的对象,既然是新的对象结果显然是false)。

为了验证我们上述我说的,我们看一下IntegerCache类的底层实现。下面为源码:

 /**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM 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;
            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() {}
    }

看源码中的注释我们知道,我们可以通过Jvm中的AutoBoxCacheMax参数来重新设置IntegerCache类的缓存范围。并且我们知道IntegerCache类使用了Integer cache[] 数据缓存数值。


这就是上述面试题中所要考察的相关知识,实际上除IntegerCache类之外,在Java中还提供了ByteCache、ShortCache、LongCache、CharacterCache等缓存对象,其中前三个缓存对象的缓存范围都是-128 到 127。而CharacterCache缓存对象则是0到127。这就是Java中IntegerCache类相关的知识,如有考虑不周,或者输写有误的地方,欢迎留言,谢谢。

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧