为什么重写 equals 时必须重写 hashCode ⽅法?怎么重写hashcode?看完吊打面试官!!(通俗易懂)

为什么重写 equals 时必须重写 hashCode ⽅法?

因为两个相等的对象的 hashCode 值必须是相等。也就是说如果 equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。

如果重写 equals() 时没有重写 hashCode() 方法的话就可能会导致 equals 方法判断是相等的两个对象,hashCode 值却不相等。

为什么两个相等的对象的 hashCode 值必须是相等?因为因为基于哈希的集合类(如 HashSet、HashMap、Hashtable 等)依赖于这一点来正确存储和检索对象

比如HashSet ,当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashCode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashCode 值作比较,如果没有相符的 hashCodeHashSet 会假设对象没有重复出现。但是如果发现有相同 hashCode 值的对象,这时会调用 equals() 方法来检查 hashCode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

也就是说:

  • 如果两个对象的hashCode 值相等,那这两个对象不一定相等(哈希碰撞)。
  • 如果两个对象的hashCode 值相等并且equals()方法也返回 true,我们才认为这两个对象相等。
  • 如果两个对象的hashCode 值不相等,我们就可以直接认为这两个对象不相等。

问题来了?

怎么重写hashcode?

怎么重写才能保证如果 equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值(哈希码)也要相等?

我们知道,object类的哈希码是由对象的内存地址得来的,现在重写了equal方法,一般是比较类的属性是否相同,所以,哈希码也应该和由属性(的哈希值)计算而来,我们一般是通过某个公式将所有属性带入计算得到哈希码。

例子:

package Test;

public class Person3 {
    private String name;
    private String idCard;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getIdCard() {
        return idCard;
    }
    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public Person3() {}

    public Person3(String name, String idCard) {
        this.name = name;
        this.idCard = idCard;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((idCard == null) ? 0 : idCard.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    public static void main(String[] args) {
        Person3 p1 = new Person3("赵四", "41081234");
        Person3 p2 = new Person3("赵四", "41081234");
        System.out.println("p1的hashCode是" + p1.hashCode());
        System.out.println("p2的hashCode是" + p2.hashCode());
    }
}
package Test;

public class Person3 {
    private String name;
    private String idCard;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getIdCard() {
        return idCard;
    }
    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public Person3() {}

    public Person3(String name, String idCard) {
        this.name = name;
        this.idCard = idCard;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((idCard == null) ? 0 : idCard.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    public static void main(String[] args) {
        Person3 p1 = new Person3("赵四", "41081234");
        Person3 p2 = new Person3("赵四", "41081234");
        System.out.println("p1的hashCode是" + p1.hashCode());
        System.out.println("p2的hashCode是" + p2.hashCode());
    }
}

这段代码的运行结果为:

p1的hashCode是1301683616
p2的hashCode是1301683616

在我们重写hashCode()方法后,可以看到两个属性值完全相同的对象,他们的哈希值是相同的。从业务的角度来说,达到了这两个对象相同的目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为什么不辞而别

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值