Integer对象之间的比较要考虑到对象初始化的不同情况,初始化又涉及到对象包装器类的自动装箱特性 。
自动装箱
Integer是一种对象包装器类。对象包装器类是不可变的,也就是说,一旦完成了构造,包装在其中的值就不可以再被更改了。包装器类有一种特性,自动装箱。当需要一个Integer类型的对象时,可以对int类型的元素进行自动打包的操作。如果添加3到list中,实际调用的是下面的代码。
ArrayList<Integer> list = new ArrayList();
list.add(3);
list.add(Integer.valueOf(3));
valueOf的源代码如下
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
其中IntegerCache定义如下
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 =
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() {}
}
JVM会维护一个Integer的数组,将值在某个范围内(默认-128~127)的对象缓存起来,在这个范围内的int会被包装到固定的对象中,valueOf会返回缓存中的对象。如果不在这个范围内,则会创建一个新的对象。注意,使用new创建的新对象是在堆中的,这一点会影响到Integer对象之间的比较结果。
自动拆箱
与自动装箱对应的,存在自动拆箱操作。当将一个Integer对象赋值给一个int值时,编译器就会插入对象拆箱指令。
int n = list.get(i);
int n = list.get(i).intValue();
intvalue()源代码就很简单了,返回对象的value属性
public int intValue() {
return value;
}
Integer初始化
1.
初始化Integer的时候,可以直接用一个int值赋值,实际上会自动装箱。
Integer n1 = 3;
Integer n1 = Integer.valueOf(3);
2.
当然也可以使用new来创建Integer对象.
Integer n2 = new Integer(3);
Integer对象之间的比较
由于IntegerCache的存在,使用第一种方法初始化的对象,如果值的范围在-128~127之间,则相同的值会被包装的同一对象中。而用new产生的对象肯定不会在同一内存区域。
==运算符
如果使用==运算符进行比较的话,由于检测的是对象是否指向同一个内存区域,由于初始化时的不确定性,比较的结果也可能不是我们想要的。如下所示:
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
Integer n3 = 47;
Integer n4 = 47;
Integer n5 = 200;
Integer n6 = 200;
System.out.println(n1 == n2); //false,两个new的对象
System.out.println(n1 == n3); //false n1在堆中,n3指向IntegerCache缓存(方法区中)
System.out.println(n3 == n4); //true 都指向缓存中同一个对象
System.out.println(n5 == n6); //false 超出缓存范围,分别是两个new出来的对象
equals
所以为了保持对象之间比较结果的一致性,同时我们进行比较的初衷应该也是比较它们之间的值,所以使用equals方法
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
Integer类重写了object的equals方法,调用时实际比较的是两个对象的值,和对象存储在哪里没有关系。