在java编程中,自动装箱和拆箱,相信大家都不陌生,但是在比较过程中,会有一些坑,尤其是业务代码复杂的时候,比较容易掉进去。今天就说一下,我遇到的一个基本类型比较的问题。
WrapperClass缓存
在基本类型的wrapperClass中,有些是有缓存的,比如Integer。
/**
* 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[];
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() {}
}
以上为Integer的缓存,可以看到对于-128到127的Integer在java运行的时候已经作为trust类被加载到jvm中,当然他的IntegerCache类也被初始化完成。
valueOf&intValue
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
这是自动装箱的使用方法,大家可以自己编写一个自动装箱的测试代码,然后通过javap -c命令查看的反编译代码。看到装箱的过程中,使用了IntegerCache中缓存好的Integer。
public int intValue() {
return value;
}
自动拆箱方法
new
Integer的new方法和其他对象没什么区别。肯定需要开辟新的对象空间。一个新的对象。
小结
通过以上,我们可以看到Integer的装箱和拆箱的原理,然后我们平时使用到的比较的时候就需要注意。
- 如果都是通过自动装箱获得的Integer,如果都在[-127,128]中,那么直接对比的是cache中的对象的引用,也可以间接的达到比较值的作用。
- 如果Integer的值在[-127,128]这个范围外部,那么执行new Integer(i)方法,创建新的对象。==号的作用,失去了间接比对的作用。
综上所述:如果碰到了WrapperClass比较的情况,直接使用CompareTo方法比较。使用==虽然在小值可以间接达到自己的目的,但是很容易掉进这个坑。排查比较困难。
当然除了Integer还有其他的WrapperClass也使用了Cache,如下:
类型 | cache范围 |
---|---|
Byte | [-128,127] |
Short | [-128,127] |
Integer | [-128,127] |
Long | [-128,127] |
Boolean | true,false |
Character | [0,127] |
Double | 无cache |
Float | 无cache |