文章目录
参考文章
前言
为方便描述,本文中所有的包装类、缓存池,都以Integer类举例。
注意:Float和Double没有缓存池
1.初探包装类的缓存池
1.1.什么是缓存池
Integer缓存池在创建时,将值∈[-128, 127]的Integer对象预先存储在一个变量名为cache的Integer数组中。每当程序调用Integer.valueOf( int )来获取Integer对象时,会判断int的值是否在[-128, 127]:
- 在,将引用指向cache中的缓存对象;
- 不在,创建新的对象(开辟新的内存空间)并将引用指向该对象,本质上是 new Integer( int )。
1.2.什么时候会创建缓存池
Integer类被加载时创建缓存池
Integer缓存池(Integer的静态内部类)的源码如下:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
int h = 127;
String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
在Integer类被加载时,静态成员就会被加载。而IntegerCache是Integer类的静态内部类,因此Integer类被加载时,就会创建缓存池。
2.自动装箱与拆箱
// 装箱:Integer.valueOf(int)
Integer boxingI = 100;
// 拆箱:int.intValue();
int i = boxingI;
2.1.自动装箱
自动将基本数据类型转换成包装数据类型。下方两段代码在运行时是等价的:
// 触发自动装箱
Integer boxingI = 100;
// 手动装箱
Integer boxingI = Integer.valueOf(100);
换言之,当程序执行到Integer packI = 100;
时,实际上程序调用了包装类的static valueOf( int )
public static Integer valueOf(int i) {
// 如果数值在缓存池范围内,从缓存池获取对象
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
// 如果不在范围内,new一个新的对象并返回
return new Integer(i);
}
- 若数值在缓存池范围内,从缓存池中获取对象(不会创建新对象);
- 若数值不在缓存池范围内,创建一个新的Integer对象。
2.2.拆箱
将包装数据类型变成基本数据类型(注意:这里不涉及向上转型和向下转型,因为int不是类)
Integer boxingI = 100;
// 拆箱
int i = boxingI;
Integer boxingI = 100;
// 拆箱
int i = boxingI.intValue();
intValue( )是非静态的成员方法,而intValue( )的源码非常简单:
public int intValue() {
return value;
}
3.Integer.valueOf( int )和new Integer( int )
从Integer.valueOf( int )的源码得知,当传入的int不在缓存池范围内,就会**new Integer( **int )。
- 若在缓存池范围内,从缓存池获取对象。
- 若不在缓存池范围内,创建新的对象。
Integer i1 = Integer.valueOf(100);
Integer i2 = Integer.valueOf(100);
Integer i3 = new Integer(100);
System.out.println(i1 == i2); // true - 都是缓存池中的同一个对象
System.out.println(i1 == i3); // false - i1是缓存池中的对象,i3是新建的对象