1、缓存范围
默认情况下,Integer缓存预先创建并存储了值在 -128
到 127
之间的整数对象。这个范围是固定的,因为它被定义为标准Java规范的一部分。-128
到 127
范围内的整数使用非常频繁,重用这些对象可以显著节省内存。
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
的内部静态类,该类包含一个缓存数组,其中存储了 -128
到 127
之间的 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 } }