????????前两天看了篇帖子,两个Integer对象做比较时,会产生意想不到的结果。想起之前也有遇到这样的情况,一直没有总结,今天简单记录一下。
相信大家一定遇到过这样的问题:==与equals有什么不同?
????????两者都需要区分基本数据类型与非基本数据类型。
????????对于==来说,如果是基本数据类型则比较值是否相等,如果是(非基本数据类型)对象则比较指向该对象的引用是否相等。
举个小例子:
Integer a = 100;
Integer b = 100;
System.out.println(a == b);// true
Integer c = 1000;
Integer d = 1000;
System.out.println(c == d);// false
然而
int e = 1000;
int f = 1000;
System.out.println(e == f);// true
那么为什么呢?
????????Java的8中基本类型分别是:byte、short、int、long、float、double、char和boolean。
????????Integer作为int类型的包装类型,并不属于Java中的8种基本类型。在Java中,除了上面的这8种类型,其他的类型都是对象,保存的是引用,而非数据本身。
????????至于为什么两次比较的结果不一致,暂且别急,先看看下面的问题:
Integer a = 1000;
Integer a = new Integer(1000);
// 这两者的区别在哪里?
????????对于前者来说,当你将一个基本类型值直接赋给一个包装类型的变量时,编译器会自动进行装箱操作,将基本类型值包装成对应的包装类型对象。
????????而后者这种方式使用了显式的构造函数调用。在这种情况下,通过使用构造函数new Integer(1000)来创建一个新的Integer对象。这种方式会在堆内存中为每个新创建的对象分配不同的内存空间,即使两个Integer对象的值相同。
? ? ? ? 要注意的是,前者写法并不是后者的简写形式。对后者来说其正确的简写形式为:
Integer a = Integer.valueOf(1000);
????????在定义对象a和b时,Java自动调用了Integer.valueOf来将数字封装成对象。
// Integer源码:
@IntrinsicCandidate
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
如果数字在low和high之间的话,是直接从IntegerCache缓存中获取的数据。
// IntegerCache源码:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer[] cache;
static Integer[] archivedCache;
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
h = Math.max(parseInt(integerCacheHighPropValue), 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
// Load IntegerCache.archivedCache from archive, if possible
CDS.initializeFromArchive(IntegerCache.class);
int size = (high - low) + 1;
// Use the archived cache if it exists and is large enough
if (archivedCache == null || size > archivedCache.length) {
Integer[] c = new Integer[size];
int j = low;
for(int i = 0; i < c.length; i++) {
c[i] = new Integer(j++);
}
archivedCache = c;
}
cache = archivedCache;
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
????????也就是说,如果数字在-128~127,是直接从 缓存 中获取的Integer对象。如果数字超过了这个范围,则是new出来的新对象。
????????文章中的1000,超出了-128~127的范围,所以对象a和b的引用指向了两个不同的地址;而100在-128~127的范围内,对象a和b的引用指向了同一个地址。
为什么Integer类会加这个缓存呢?
????????因为-128~127是使用最频繁的数字,如果不做缓存,会在内存中产生大量指向相同数据的对象,会浪费部分内存空间。