包装类的缓存问题
一、手册规则
【强制】所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。
说明:对于 Integer var = ? 在-128 至 127 范围内的赋值,Integer 对象是在IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。
二、案例分析
1.Integer缓存问题分析
我们先看下面的示例代码并思考该代码输出的结果。
代码如下(示例):
public class IntTest {
public static void main(String[] args) {
Integer a = 100, b = 100, c = 150, d = 150;
System.out.println(a == b);
System.out.println(c == d);
}
}
程序运行的结果是true,false。
你的思考结果是什么呢?
如果你的结果和程序运行结果一致,那为什么答案是这样的呢?
你的回答可能是Integer包装类对象的值如果在-128到127之间,会复用已产生的对象。
但,答案真的是这样么?
通过对Integer a = 100打断点进行调试分析得出,会调用Integer.valueOf(int i)这个方法。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
通过源码可知,通过Integer.valueOf()来创建的整型对象,参数大于等于IntegerCache.low并且小于等于IntegerCache.high,就会从缓存数组中提取值。如果不在这个范围,就会重新new 一个整型对象。
那么low和high的值,是多少呢?
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");
// 省略其它代码
}
// 省略其它代码
}
通过这段源码分析,我们可以得出:最小值是固定值(-128),最大值不是固定值。缓存的最大值是可以通过虚拟机参数 或 java.lang.Integer.IntegerCache.high 来设置的,未指定则为 127。
如果将最大值设置的结果大于等于150,那么上面示例结果:true,true;
同理分析其他包装类的缓存问题。
2.Long缓存问题分析
同理,我们接下来分析java.lang.Long#valueOf(long)的源码。
代码如下(示例):
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);
}
通过java.lang.Long#valueOf(long)来创建对象,如果参数大于等于-128并且小于等于127,就会从缓存对象数组中提取。
LongCahce源码如下
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);
}
该处使用的url网络请求的数据。
3.Character缓存问题分析
public static Character valueOf(char c) {
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
通过源码可知,使用java.lang.Character#valueOf()来创建对象,如果参数小于等于127,会从缓存对象数组中提取值;并且127是缓存范围的最大值。
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);
}
}
通过CharacterCache类源码可知,是在静态的长度为128的缓存对象的数组中填充值。
4.Short缓存问题分析
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,127】。
三、总结
包装类型 | 基本数据类型 | 缓存对象(基本数据类型值) |
---|---|---|
Boolean | boolean | true,false(全部值) |
Byte | byte | -128~127(全部值) |
Short | short | -128~127 |
Character | char | 0~127 |
Long | long | -128~127 |
Integer | int | -128~127(默认为127) |