为什么重写 equals方法时一定要重写hashCode方法?

原文地址

原理

重写equals方法时一定要重写hashCode方法的原因是为了保证对象在使用散列集合(如HashMap、HashSet等)时能够正确地进行存储和查找。

案例

多说无益,直接开始实践

测试方法

void testStudent() {
    Map<Student, String> studentMap = new HashMap<>();
    Student student1 = new Student("Alice", 1);
    Student student2 = new Student("Alice", 1);
    studentMap.put(student1, "A");
    System.out.println("hashcode是否相等 "+ (student1.hashCode() == student2.hashCode()));
    System.out.println("对象是否相等 "+ (student1.equals(student2)));
    System.out.println(studentMap.get(student2));
}

测试一

Student类(未重写equals和hashcode)

public class Student {
    private String name;
    private int id;

    public Student(String name, int id) {
        this.name = name;
        this.id = id;
    }
}

image-20230701002002053

可以看到,当我们两个方法都未进行重写的时候,对象和hashCode都不一致,所以当我们存进散列表的时候,会一直存放进我们认为相同的对象,也就是并不唯一。

测试二

Student类(重写equals,未重写hashcode)

public class Student {
    private String name;
    private int id;

    public Student(String name, int id) {
        this.name = name;
        this.id = id;
    }

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

image-20230701002049947

为什么对象相等,但是还是找不到该student对象呢?因为散列表找的时候,首先是调用hashcode去进行寻找是否有重复的对象,如果不重复就表示没有找到,如果有该hashcode,就需要再调用一次equals判断是否真正相等(哈希冲突)。你可以试一下,只重写hashcode,但是不重写equals,最后还是取不到该对象。

带你深入一下源码,看一下过程。以下只截取主要核心的代码

//测试方法中的查找方法get,鼠标点进去
studentMap.get(student2)

image-20230701003008191

    public V get(Object key) {
        Node<K,V> e;
        //首先调用了hash,获取hash值,再调用getnode,这里点进去hash方法
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

    static final int hash(Object key) {
        int h;
        //可以看到,这里最后调用了hashcode的方法,而hashcode是native方法,下面放JavaGuide对
        //hashcode的解释
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

    public native int hashCode();

    //所以首先先获取hash值,如果在散列表找到,才需要去调用equals,我们进入getNode方法进去看看
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            //看一下这里,如果散列表中不为空,表示可能有对应的值
            (first = tab[(n - 1) & hash]) != null) {
            //然后再调用一次equals判断对象是否相等
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

image-20230701003314628

测试三

Student类(重写equals和hashcode)

public class Student {
    private String name;
    private int id;

    public Student(String name, int id) {
        this.name = name;
        this.id = id;
    }

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

    @Override
    public int hashCode() {
        return Objects.hash(name, id);
    }
}

image-20230701002157915

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇