99网
您的当前位置:首页为什么我们自定义的对象重写了equals方法,同时也必须重写hashCode方法?

为什么我们自定义的对象重写了equals方法,同时也必须重写hashCode方法?

来源:99网

这是因为散列的数据结构(HashMap,HashSet等)用到了hashCode和equals方法。
当我们自定义了一个类,例如Student,这个类有一个String类型属性name。

如果我们认为name相同的对象就是同一个人,那么我们就应该重写equals方法
class Student{
    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(name, student.name);
    }

}

此时我们未重写hashCode方法。
关键点来了:
我们new了两个名字为张飞的对象,我们认为这是同一个人,将s1作为键放入HashMap中,然后我们通过s2取,理论上应该也是能取出来的,因为我们认为是同一个人作为键,但是,却取不出来:

public static void main(String[] args) {
    Student s1 = new Student("张飞");
    Student s2 = new Student("张飞");

    Map hashMap = new HashMap();
    
    hashMap.put(s1,"waqng");

    System.out.println(hashMap.get(s2));
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        // 如果是首次添加,则初始化数组
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
         // 位与运算得出索引位置,看此位置是否已有节点,没有最好,那么直接放入
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
         // 走到这里说明数组已经完成初始化,并且发生了hash碰撞,需要做进一步判断
        else {
            Node<K,V> e; K k;
            // 这就是咱们所探讨的主题
            // 数组的这个位置已经有了节点元素存在,那么进行判断:
            // 此位置元素的key的hash值要是与我们新插入的hash值相等,并且key的地址值相等(也就是同一个对象)或者调用了key的equals方法返回值相等,那么我们认为这两个key是一个,则进行值的覆盖,并且返回旧值。(省略了后面源码)
            // 拿我们的例子来解释:因为是两个对象,那么地址值肯定不相等了,所以要想让这个if为true,就必须让这两个名为张飞的student对象的hashCode相等,并且equals方法返回true
            // 我们重写了equals方法,两个对象名字相同,返回true成立。但是未重写hashCode方法,两个对象的hashCode方法默认是地址值,那么就不会相等了,所以条件不成立,也就是不认为两个“张飞”是同一个key
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                。。。。。。。。
            else {
                。。。。。。。。
            }
            if (e != null) { // existing mapping for key
                。。。。。。。
            }
        }
        。。。。。。。
        return null;
    }
如果我们不通过name是否相同来判断是不是一个人,而是单纯通过对象的地址值进行判断,那么就不需要重写equals和hashCode方法

因篇幅问题不能全部显示,请点此查看更多更全内容