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
}
}