Java Integer包装类缓存(cache)

Java的Integer类有一个内部的缓存机制,主要用于优化自动装箱(autoboxing)和拆箱(unboxing)的性能。这个特性首次引入于Java 5,旨在减少对频繁使用的小整数值的重复对象创建,从而提高性能和减少内存使用。

1、缓存范围

默认情况下,Integer缓存预先创建并存储了值在 -128127 之间的整数对象。这个范围是固定的,因为它被定义为标准Java规范的一部分。-128127 范围内的整数使用非常频繁,重用这些对象可以显著节省内存。

public class Main {
  public static void main(String[] args) {
	  Integer integer1 = 3;
		Integer integer2 = 3;
		if (integer1 == integer2)
			System.out.println("integer1 == integer2");
		else
			System.out.println("integer1 != integer2");
		Integer integer3 = 300;
		Integer integer4 = 300;
		if (integer3 == integer4)
			System.out.println("integer3 == integer4");
		else
			System.out.println("integer3 != integer4");

  }
}

2、自动装箱

Integer 类是 int 类型的包装类,它提供了一系列方法来操作 int 数据,并且是集合框架(如 ArrayList 和 HashMap)中使用的类。Java 为了优化性能和内存使用,在 Integer 类中实现了一个缓存机制,这个机制与自动装箱(Autoboxing)紧密相关。当一个基本类型的int值在这个范围内时,通过自动装箱转换为Integer对象,Java会直接从缓存中返回已存在的对象,而不是创建一个新的Integer实例。

public class Main {
  public static void main(String[] args) {
    Integer a = 100; // 自动装箱,使用缓存
    Integer b = 100; // 自动装箱,使用缓存
    System.out.println(a == b); // true,因为 a 和 b 指向相同的缓存对象
    
    Integer c = 200; // 自动装箱,不在缓存范围,创建新对象
    Integer d = 200; // 自动装箱,不在缓存范围,创建新对象
    System.out.println(c == d); // false,因为 c 和 d 指向不同的对象

  }
}

3、配置缓存大小

虽然标准的缓存大小是固定的,但是可以通过JVM启动参数 -XX:AutoBoxCacheMax=size 来设置缓存的上限。可以缓存更大范围内的整数值,但应谨慎使用,因为这会增加JVM启动时的内存占用。

4、Java Integer包装类缓存的实现

Java 5 中引入了 Integer 包装类的缓存机制,旨在节省内存和提升性能。该机制对 -128 127 之间的 Integer 对象进行缓存,当需要使用在这个范围中某个值 的 Integer 对象时,会直接从缓存中返回,而不是每次都创建新的对象。Integer 类有一个名为 IntegerCache 的内部静态类,该类包含一个缓存数组,其中存储了 -128127 之间的 Integer 对象。

Java JDK 1.8.0 build25的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.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

IntegerCache是在Integer类中私有的(private)静态内部类,代码如下,

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

5、其它包装类对象缓存

包装类缓存是不仅仅应用在Integer包装类对象,ByteCache缓存Byte对象,ShortCache缓存Short对象,LongCache缓存Long对象,CharacterCache缓存Character对象。

public class Main {
  public static void main(String[] args) {
        Byte b1 = 127;
        Byte b2 = 127;
        System.out.println(b1 == b2); // true

        Byte b3 = new Byte((byte) 127);
        System.out.println(b1 == b3); // false
        
        
        Short s1 = 127;
        Short s2 = 127;
        System.out.println(s1 == s2); // true

        Short s3 = new Short((short) 127);
        System.out.println(s1 == s3); // false
        
        
        Long l1 = 127L;
        Long l2 = 127L;
        System.out.println(l1 == l2); // true

        Long l3 = new Long(127L);
        System.out.println(l1 == l3); // false
        
        
        Character c1 = 'a';
        Character c2 = 'a';
        System.out.println(c1 == c2); // true

        Character c3 = new Character('a');
        System.out.println(c1 == c3); // false

  }
}

    推荐阅读
    cjavapy编程之路首页