Integer
Integer内部有一个IntegerCache
类,这个类用来缓存int
型数值,默认缓存的范围是-128 ~ 127,如果设置了系统属性java.lang.Integer.IntegerCache.high
,则获取这个系统属性,之后进行比对:
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
正常情况下,上限要么还是127,要么就是java.lang.Integer.IntegerCache.high
, 如果该系统属性比Integer.MAX_VALUE - 128 - 1
还大, 那么上限就是Integer.MAX_VALUE - 128 - 1
(有谁会那么蛋疼的把上限设这么高?.), 确定好上限后,会初始化内部的缓存数组:
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
预先放入-128 ~ 127范围内的Integer
对象
当调用Integer.valueOf(int)
时, 会首先判断传入的int值是不是在-128127范围内,如果从`ImageCache`中直接获取`Integer`对象,这样避免了重新创建一个Integer的内存开销;如果不在-128127范围内,那么就直接生成一个新的Integer
, 代码如下:
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Integer
内部有缓存,那么同样都是装箱对象的Double
,Long
等类型会有缓存吗?
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));
}
}
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
}
Byte
是基础类型byte
的装箱类,一个byte代表的是一个字节,刚好是-128 ~ 127,所以Byte
装箱类缓存了byte
可能的所有值
Short
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));
}
}
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);
}
可以看到Short
也是缓存了-128 ~ 127范围内的值
Long
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);
}
}
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);
}
Long
内部也使用了缓存,范围也同样是-128 ~ 127
Double、Float
public static Float valueOf(float f) {
return new Float(f);
}
public static Double valueOf(double d) {
return new Double(d);
}
可以看到, Double
, Float
内部并没有使用缓存,而是每次都是直接生成一个新的对象
为什么这两个类没有做缓存呢?因为没意义……这两个类代表的都是浮点数,从Integer, Short,Byte中可以看到,缓存至多存256个数,缓存太多反而会占用更多内存,而浮点数是包含小数点后面的数,如果要缓存256个数,应该怎么选范围呢?还是-128~127?那126.01怎么办,没有缓存到啊,126.10也没有缓存到,所以对于浮点数来说缓存命中率太低,还不如不缓存,省的浪费内存