Integer类的缓存机制

存在下述例子,判断其输出结果。

public class Main{
	public static void main(String[] agrs){
		Integer a = 110;
		Integer b = 110;
		Integer c = 150;
		Integer d = 150;
		System.out.println("a == b: " + (a == b));
		System.out.println("c == d: " + (c == d));
	}
}

我们知道,在Java中存在基本数据类型和引用数据类型,而Integer作为int的封装类,Integer实例化的对象应是引用数据类型。所以,也许新手会认为是下述结果:

a == b: false
c == d: false

但是,通过运行可以发现,程序输出结果是:

a == b: true
c == d: false

原因
我们知道,在直接对一个Integer对象赋值时,会调用java.lang.Integer#valueOf(int i)方法 (可以通过断点的方式验证),该方法源码如下:

/**
	 * 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缓存数组中,
		// 若存在则直接返回已缓存的实例,提高程序性能,
		// 若不存在,则通过 new Integer(i) 实例化返回。
		if (i >= IntegerCache.low && i <= IntegerCache.high)
			return IntegerCache.cache[i + (-IntegerCache.low)];
		return new Integer(i);
	}

根据源码注释,可知:会返回一个指定的int值的Integer实例。若不需要一个新的Integer实例,会优先采用该方法实例化,而不是new Integer(int i)。因为相比于使用new Integer(int i)的方法实例化对象,valueOf(int i)会缓存经常请求的值 (多次请求会从缓存中获得),从而获得更好的空间和时间性能。
通过阅读源码,发现Integer类中存在一个静态内部类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[]; // final修饰,不可变,仅在第一次使用时初始化

		static {
			// high value may be configured by property
			// 可以通过属性设置high上限值
			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]内的Integer对象,且采用一个final修饰的数组cache作为存储容器,首次使用时会初始化该缓存。此外,缓存的上限是可以修改的,通过修改选项:-XX:AutoBoxCacheMax=来设置缓存上限值。
其他缓存对象
不止是Integer类,其他整数类型的类都存在类似的缓存机制。
如:
ByteCache缓存Byte对象;
ShortCache缓存Short对象;
LongCache缓存Long对象;
CharacterCache缓存Character对象;
对于Byte、Short、Long、Character的缓存范围是固定的,不可修改,其中:
Byte、Short、Long的缓存范围为[-128, 127];
Character的缓存范围是[0, 127]
总结

综上所述,对Integer赋值[-128, 127],会使用Integer类的静态内部类IntegerCache返回缓存实例,且该上限值是可以自定义的,一般情况下都是采用默认值。

上一篇:JAVA基础- 为啥 Integer 中100=100 为true 而200=200则为false


下一篇:mysql中这样解决数据排序和分组排序