缓存池源码解读
编译器会在自动装箱过程调用 valueOf() 方法,因此多个值相同且值在缓存池范围内的 Integer 实例使用自动装箱来创建,那么就会引用相同的对象。
new Integer(123) 与 Integer.valueOf(123) 的区别在于:
- new Integer(123) 每次都会新建一个对象;
- Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。
基本类型对应的缓冲池范围如下:
- boolean values true and false【true,false】
- all byte values【-128~127】
- short values between -128 and 127【-128~127】
- int values between -128 and 127【-128~127】
- long values between -128 and 127【-128~127】
- char in the range \u0000 to \u007F【0~127】
下面我们对包装类型缓存池源码进行一一解读
public static void main(String[] args) throws CloneNotSupportedException {
Byte a = Byte.valueOf("12");
Character character = Character.valueOf('1');
Boolean aBoolean = Boolean.valueOf("true");
Short aShort = Short.valueOf("123");
Integer integer = Integer.valueOf("123");
Long aLong = Long.valueOf("123");
Float aFloat = Float.valueOf("123");
Double aDouble = Double.valueOf("123");
}
1. Byte.valueOf("A");
byte即字节的意思,由8位组成,即其可以表示的最大值为
我们通过下面分析可知,Byte的缓存池大小为-128到127,即Byte的缓存池为all byte values。
我们点进valueOf方法
public static Byte valueOf(String s) throws NumberFormatException {
return valueOf(s, 10);
}
valueOf方法调用重载的valueOf,参数10指10进制转换后面用。
public static Byte valueOf(String s, int radix)
throws NumberFormatException {
return valueOf(parseByte(s, radix));
}
重载valueOf再调用一个重载方法,传入一个parseByte的结果
public static byte parseByte(String s, int radix)
throws NumberFormatException {
int i = Integer.parseInt(s, radix);
if (i < MIN_VALUE || i > MAX_VALUE)
throw new NumberFormatException(
"Value out of range. Value:\"" + s + "\" Radix:" + radix);
return (byte)i;
}
Integer.parseInt
方法将字符串转换为数字,radix我们知道前面传入的是10,因此s传入的值只能是十进制数字表示的字符串,否则会报NumberFormatException。
下面也对i的值进行了限制,本类的静态变量MAX_VALUE = 127,MIN_VALUE = -128。
最后将i强转为一个byte。
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
}
这里定义了一个偏移量128,因为负数在二进制中不方便表示,这里对实际值+128存储,即-128实际存储为0000 0000。
然后返回ByteCache.cache数组中对应下标的byte。
private static class ByteCache {
private ByteCache(){}
static final Byte cache[] = new Byte[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Byte((byte)(i - 128));
}
}
这个类就是缓存池本池了,一个静态内部类里的静态不可变变量cache数组即是Byte的缓存池。
该数组的初始化容量为256,且通过静态代码块开始就将所有数据进行了初始化。
2. Character.valueOf('1');
public static Character valueOf(char c) {
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
此处char小于等于127获取缓存池中的值,否则会new一个Character对象。
这里求一个java中不走缓存值的示例😂
private static class CharacterCache {
private CharacterCache(){}
static final Character cache[] = new Character[127 + 1];
static {
for (int i = 0; i < cache.length; i++)
cache[i] = new Character((char)i);
}
}
Character的缓存池本池,一个静态内部类里的静态不可变变量cache数组。
该数组的初始化大小为128,且通过静态代码块进行了初始化,且与ASCII码表对应
3. Boolean.valueOf("true");
public static Boolean valueOf(String s) {
return parseBoolean(s) ? TRUE : FALSE;
}
public static boolean parseBoolean(String s) {
return ((s != null) && s.equalsIgnoreCase("true"));
}
判断s是不是字符串TRUE,是则返回TRUE,否则返回FALSE。
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
即Boolean的缓存池就是true和false两个静态不可变的包装对象。
4. Integer.valueOf("123")
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
调用重载方法,调用本类parseInt方法,转换进制为10进制,因此同byte只能传入数字表示的字符串。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
IntegerCache.low
到IntegerCache.high
之间的值从缓存池中获取,否自new一个新的Integer对象。
偏移量是(-IntegerCache.low)即128。
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() {}
}
IntegerCache缓存池本池:一个静态内部类里的静态不可变变量cache数组。
low = -128
:缓存池最小值-128,heigh
:取一个环境变量的配置,如果存在使用该值,不存在使用默认值127。
同样通过静态代码块进行了初始化,偏移量是(-IntegerCache.low)即128。
5. Short.valueOf("123");
public static Short valueOf(String s) throws NumberFormatException {
return valueOf(s, 10);
}
调用重载方法,传入radix,10进制转换。
public static Short valueOf(String s, int radix)
throws NumberFormatException {
return valueOf(parseShort(s, radix));
}
调用重载方法,传入parseShort的返回值。
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
if (sAsInt >= -128 && sAsInt <= 127) { // must cache
return ShortCache.cache[sAsInt + offset];
}
return new Short(s);
}
偏移量128,-128到127之间的数从缓存池获取,其他new Short(s);
private static class ShortCache {
private ShortCache(){}
static final Short cache[] = new Short[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Short((short)(i - 128));
}
}
ShortCache缓存池本池:一个静态内部类里的静态不可变变量cache数组。静态代码块中进行初始化数据。
6. Long.valueOf("123");
public static Long valueOf(String s) throws NumberFormatException
{
return Long.valueOf(parseLong(s, 10));
}
调用重载构造方法,传入parseLong的返回值
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
偏移量128,-128到127之间的数从缓存池获取,其他new Long(s);
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
LongCache缓存池本池:一个静态内部类里的静态不可变变量cache数组。静态代码块中进行初始化数据。
7. Float.valueOf("123");
public static Float valueOf(String s) throws NumberFormatException {
return new Float(parseFloat(s));
}
直接返回new Float无缓存池。
8. Double.valueOf("123");
public static Double valueOf(String s) throws NumberFormatException {
return new Double(parseDouble(s));
}
直接返回new Double无返回值。