今天在使用CollectionUtils.intersection() 的时候,发现个问题,明明两个集合中有几个完全相同的类,但是使用这个intersection 方法的时候求到的交集却是空的?
其实很简单,这个问题往往是因为没有重写对象的equal 方法导致的。
其实在使用很多工具集,在比较对象的时候,重写equal() 方法和重写hashcode 方法是很有必要的。
来看一看intersection 方法:
public static Collection intersection(Collection a, Collection b) {
ArrayList list = new ArrayList();
Map mapa = getCardinalityMap(a); //key为a的元素,value为元素出现次数
Map mapb = getCardinalityMap(b);
HashSet elts = new HashSet(a);
elts.addAll(b); //元素经hash去重后的并集
Iterator it = elts.iterator();
while (it.hasNext()) {
Object obj = it.next();
int i = 0;
//对于每个元素,如果a或b没有此元素,那么跳过;如果都有若干个,那么放入“个数较小一方”个该元素
//可以看到,不管做交集之前有多少个相同对象,只要他们hash一致,放入结果集的都是同一个对象
for (int m = Math.min(getFreq(obj, mapa), getFreq(obj, mapb)); i < m; ++i) {
list.add(obj);
}
}
return list;
}
再补充几句:
关于hashcode,可以理解为 标识当前对象状态的数字标识, Object 默认的hashcode 会返回一个内存编号;
hashcode() 方法要求:
- 当对象状态未改变时,那么多次调用返回的值必须相等;
- 两个对象equal,那么对象调用返回的值必须相等
hashCode() 方法虽然是内存编号,但是跟内存是没有关系的
为啥有了equal() 方法还要有hashCode() 方法呢?
hash 散列算法使得在hash表中查找一个记录的速度为O(1),每个记录都有自己的hashCode,散列算法按照hashcode 把记录放在合适的位置上;
当查找一个记录时,首先通过hashcode 快速定位记录的位置,然后通过equals 方法比较是否相等。
如果没有hashCode方法,那么就是一个个的比较,时间就会是O(N),性能就不好了。