您的位置:首页 > 编程语言 > Java开发

JDK中ArrayList、HashMap和HashSet的equals方法源码分析

2015-05-25 17:55 686 查看
最近遇到个坑,在分别对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 (e1.hasNext() && e2.hasNext()) {
        E o1 = e1.next();
        Object o2 = e2.next();
        if (!(o1==null ? o2==null : o1.equals(o2)))
            return false;
    }
    return !(e1.hasNext() || e2.hasNext());
}
可以看出,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 (m.size() != size())
        return false;

    try {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            K key = e.getKey();
            V value = e.getValue();
            if (value == null) {
                if (!(m.get(key)==null && m.containsKey(key)))
                    return false;
            } else {
                if (!value.equals(m.get(key)))
                    return false;
            }
        }
    } catch (ClassCastException unused) {
        return false;
    } catch (NullPointerException unused) {
        return false;
    }

    return true;
}
可以看出,当比较Map的数据时,equals方法对Key和Value同时进行了比较。对于Key的比较调用了HashMap.containsKey(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, table.length)];
         e != null;
         e = e.next) {
        Object k;
        if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(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 (c.size() != 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 map.containsKey(o);
}
其内部的map为一个HashMap类型,有HashMap的equals方法的实现可知,HashSet进行比较时,用到了对象的hasCode和equals方法。

小结

ArrayList的equals方法只用到数据项的equals方法,而HashMap和HashSet用到了数据项的hashCode和equals方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: