上善若水,厚德载物
—— 老子

今天我们从一个简单问题入手介绍一下Java的Integer缓存机制。大家先想一想下面代码的结果是什么呢?
Integer num = Integer.valueOf(12);System.out.println(num);Integer num1 = 88;Integer num2 = 88;System.out.println("num1 == num2:"+(num1 == num2));Integer num3 = 880;Integer num4 = 880;System.out.println("num3 == num4:"+(num3 == num4));Integer num5 = new Integer("88");Integer num6 = new Integer("88");System.out.println("num5 == num6:"+(num5 == num6));System.out.println("num2 == num5:"+(num2 == num5));
num1 == num2:truenum3 == num4:false
和预想的不一样呢,其本质就是因为存在Java Integer缓存机制,然后看源码详细梳理了一下,分享给小伙伴们
Java Integer 缓存机制
在Java5中,为Integer的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。
自动装箱:装箱就是自动将基本数据类型转换为包装器类型,默认调用valueOf()方法;
自动拆箱:装箱就是自动将基本数据类型转换为包装器类型,默认调用intValue()方法;
所以 Integer num1 = 88; 实质相当于Integer num1 = Integer.valueOf("88"); ,我们看valueOf方法源码如下:
/*** Returns an {@code Integer} instance representing the specified* {@code int} value. If a new {@code Integer} instance is not* required, this method should generally be used in preference to* the constructor {@link #Integer(int)}, as this method is likely* to yield significantly better space and time performance by* caching frequently requested values.** This method will always cache values in the range -128 to 127,* inclusive, and may cache other values outside of this range.** @param i an {@code int} value.* @return an {@code Integer} instance representing {@code i}.* @since 1.5*/public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}私有静态内部类: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 propertyint 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_VALUEh = 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之间的自动装箱过程。最大值 127 可以通过 JVM 的启动参数 -XX:AutoBoxCacheMax=num 修改,如下图所示:

此时再运行上面代码如下:
Integer num1 = 88;Integer num2 = 88;System.out.println("num1 == num2:"+(num1 == num2));Integer num3 = 880;Integer num4 = 880;System.out.println("num3 == num4:"+(num3 == num4));运行结果:num1 == num2:truenum3 == num4:true
如上修改Integer 最大缓存值为1000时,num3和num4也相等啦。
我们可以看到缓存实现是通过一个for循环,从小到大创建指定范围内的整数并存储在一个名为cache的整数数组中。这个缓存会在Integer类第一次被使用的时候被初始化出来。以后,就可以使用缓存中包含的实例对象,而不是创建一个新的实例(在自动装箱的情况下)。
在 Java5中引入这个特性的时候,范围是固定的-128至+127。后来在 Java6中,最大值映射到java.lang.Integer.IntegerCache.high,可以使用 JVM的启动参数设置最大值。这使我们可以根据应用程序的实际情况灵活地调整来提高性能。
为什么会选择-128到127这个范围呢?因为这个范围的整数值使用最广泛。在程序中第一次使用Integer的时候也需要一定的额外时间来初始化这个缓存。
其他缓存的对象
这种缓存行为不仅适用于Integer对象。我们针对所有整数类型的类都有类似的缓存机制。
ByteCache 用于缓存 Byte 对象(-128 ~ +127):
private static class ByteCache {private ByteCache(){}static final Byte cache[] = new Byte[-(-128) + 127 + 1];static {for(int i = 0; i < cache.length; i++)cache[i] = new Byte((byte)(i - 128));}}
有 ShortCache 用于缓存 Short 对象(-128 ~ +127):
private static class ShortCache {private ShortCache(){}static final Short cache[] = new Short[-(-128) + 127 + 1];static {for(int i = 0; i < cache.length; i++)cache[i] = new Short((short)(i - 128));}}
有 LongCache 用于缓存 Long 对象(-128 ~ +127):
private static class LongCache {private LongCache(){}static final Long cache[] = new Long[-(-128) + 127 + 1];static {for(int i = 0; i < cache.length; i++)cache[i] = new Long(i - 128);}}
有 CharacterCache 用于缓存 Character 对象(0 ~ +127):
private static class CharacterCache {private CharacterCache(){}static final Character cache[] = new Character[127 + 1];static {for (int i = 0; i < cache.length; i++)cache[i] = new Character((char)i);}}
Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。
或许有时候有些基础东西我们注意不到,但是某些机制和思想我们还是可以学习的。好啦,Java的Interger缓存机制就总结到这里,欢迎小伙伴们评论区交流哦








