HashMap中的equals()方法

JDK版本为1.8

使用HashMap什么时候需要重写equals方法?

当需要把自己声明的类的对象用作HashMap中的key值时,由于HashMap中get()与put()方法的实现中大量运用了equals方法对key元素的散列与查找进行比较操作,若希望携带自创类型为key或value的HashMap在散列时能够均匀、在存取时能够精准,需要在自己创建的类中重写类的equals方法,进而不去调用Object类的equals方法。

class Person{
    private String name;
    private String IDcard;

    public boolean equals(Person p){
        if(this.IDcard!=null || this.IDcard,equals(p.IDcard))
            return true;
        return false;
    }


}

此处只是源码的简单分析,而对于HashMap的详细工作原理,还是要归根结底到get,put等方法的实现

下面是HashMap中的静态内部类Node的equals方法的源码

public final boolean equals(Object o) {
        //此处单独比较的是Node
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }

上面使用的equals方法是位于Objects类中(注意不是Object)静态的比较方法:在我看来,这里有为了避免NullPointerException异常。

public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }

在实际调用equals方法是,HashMap使用父类AbstractMap的equals,下面是AbstractMap中的equals方法:

public boolean equals(Object o) {
        //首先判断两个对象的内存地址是否相同,若相同返回true
        if (o == this)
            return true;

        //判断参数是否为Map类或它的子类
        if (!(o instanceof Map))
            return false;

        //判断两个map的size是否相同,size()是同一个类中的方法
        Map<?,?> m = (Map<?,?>) o;
        if (m.size() != size())
            return false;

        try {
            //使用迭代器遍历调用equal方法的那个map,注意entrySet方法
            //m即为上面参数赋值过的那个传入的map对象
            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) {
                    //当这个节点的value值为null时,比较key
                    if (!(m.get(key)==null && m.containsKey(key)))
                        return false;
                } else {
                    //当节点的值不为空时,比较"调用方法的对象的值"与在"参数对象"中同一key取出的值
                    if (!value.equals(m.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }

        return true;
    }

下面顺便说涉及到的一个containsKey方法,源码如下

public boolean containsKey(Object key) {
        //此处是一个简单的判断key的过程,首先获取调用此方法的对象的迭代器
        Iterator<Map.Entry<K,V>> i = entrySet().iterator();

        //当传入key为null时,判断调用对象的key是否为null
        if (key==null) {
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                if (e.getKey()==null)
                    return true;
            }
        //当传入key不为null时,判断调用对象的key是否相同,调用的equals就到了Object的,按照不同数据类型的比较方法再次比较
        } else {
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                if (key.equals(e.getKey()))
                    return true;
            }
        }
        return false;
    }
    原文作者:Juses_331
    原文地址: https://blog.csdn.net/No_Endless/article/details/60143580
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞