最近遇到个坑,在分别对ArrayList、HashMap等数据类型进行比较时,发现数据一样,但equals一直返回false。于是乎看了一下ArrayList和HashMap的源码,才恍然大悟。本文的代码摘自JDK 1.7.0。
ArrayList的equals方法:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator e2 = ((List) o).listIterator();
while (() && ()) {
E o1 = ();
Object o2 = ();
if (!(o1==null ? o2==null : (o2)))
return false;
}
return !(() || ());
}
可以看出,equals方法内部在对列表元素进行逐个比较时,调用了元素的equals方法,故需要根据需求对列表元素的equals方法进行重写。
HashMap的equals方法:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Map))
return false;
Map<K,V> m = (Map<K,V>) o;
if (() != size())
return false;
try {
Iterator<Entry<K,V>> i = entrySet().iterator();
while (()) {
Entry<K,V> e = ();
K key = ();
V value = ();
if (value == null) {
if (!((key)==null && (key)))
return false;
} else {
if (!((key)))
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
return true;
}
可以看出,当比较Map的数据时,equals方法对Key和Value同时进行了比较。对于Key的比较调用了(Object)方法,该方法最终调用到了getEntry(Object)方法,代码如下:
final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, )];
e != null;
e = ) {
Object k;
if ( == hash &&
((k = ) == key || (key != null && (k))))
return e;
}
return null;
}
该方法通过key的hashCode来获取一个hash值,进而从HashMap内部的table中获取该key对应的对象。对于value的比较,是通过调用value的equals来进行比较的。故人们常说,如果你为某个类编写了equals方法,那么应该同时编写hashCode方法,难道就是为了让HashMap进行比较时不会出错?
HashSet的equals方法,位于AbstractSet中:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection c = (Collection) o;
if (() != size())
return false;
try {
return containsAll(c);
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
}
查看containsAll的代码:
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
最终调用了HashMap的contains方法:
public boolean contains(Object o) {
return (o);
}
其内部的map为一个HashMap类型,有HashMap的equals方法的实现可知,HashSet进行比较时,用到了对象的hasCode和equals方法。
小结
ArrayList的equals方法只用到数据项的equals方法,而HashMap和HashSet用到了数据项的hashCode和equals方法