Long a = 10000L;
Long b = 10000L;
List<Long> test = new ArrayList<>();
test.add(a);
System.out.println(test.contains(b));
大家都知道,Long以及Integer 都是有个常量缓存池,为-128 到127这个范围。这个范围内的对象都是相等的。
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);
}
}
就是说
Long a = 100L;
Long b = 100L
System.out.println(a == b)
返回值为true的。因为这段区间的值属于常用值,所以即使新建在多的对象也是同一个值。
但回到上题, 笔者新建了两个Long对象,给对象赋值都超过了Long自带的常量缓存区间,所以这两个对象完全是不相等的。读者只加入了第一个对象,但运行结果是true。list集合判断包含b这个对象,可明明读者就没有往集合里添加该对象。
接下来,读者看了下源码。
从list集合接口里contains方法找到ArrayList的实现, 再定位到具体调用的方法。
public int indexOf(Object o) {
// 先判断入参是否为null
if (o == null) {
// 为null就循环判断elementData数组是否包含null
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
// 不为null就调用对象的equals方法去比较
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
调用对象的equals方法,查看Long的equals方法。
public boolean equals(Object obj) {
// 判断是否为Long对象
if (obj instanceof Long) {
// 比较的是拆箱的long类型值。
return value == ((Long)obj).longValue();
}
return false;
}
从上就可了解了为何两个不同的Long对象,只要值相同,list contains()方法就返回true。
同理,Integer,String这些不可变类的结果也是一样。这也解释了为何新建两个对象,其属性值一样,为何contains()失败。因为对象的equals()方法没有重写的话,默认就是比较地址值。