存在下述例子,判断其输出结果。
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返回缓存实例,且该上限值是可以自定义的,一般情况下都是采用默认值。