为什么重写equals方法一定要重写hashcode

引言

在说明这个问题前我们先来看一下关于hashcode的一些硬性规定:

1.两个对象equals相等,hashcode一定相等。
2.两个对象equals不等,hashcode不一定不等。
3.两个对象的hashcode相等,两个对象不一定相等。
4.两个对象的hashcode不等,两个对象一定不等。

equals方法和hashcode方法介绍

equals方法和hashcode方法都是Object类里面的两个方法。
equals的作用是比较两个对象的地址值是否相等
hashcode方法的作用是返回该对象的十六进制的地址值。
他们的源码如下:

public boolean equals(Object obj) {
        return (this == obj);
    }
    public native int hashCode();

验证结论

我们用几个例子来验证我们的程序是否遵循hashcode的硬性规定。

1.两个对象equals相等,hashcode一定相等。

public class Student {
    public static void main(String[] args) {
        Student student1= new Student("wf", "man");
        Student student2 = new Student("wf", "man");
        System.out.println(student1.equals(student2));
        System.out.println(student1.hashCode()==student2.hashCode());
    }
    private String name;
    private String sex;

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

    @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) && Objects.equals(sex, student.sex);
    }

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

true
true

2.两个对象equals不等,hashcode不一定不等也可能相等。

public class Student {
    public static void main(String[] args) {
        Student student1= new Student("wlf", "man");
        Student student2 = new Student("wf", "man");
        System.out.println(student1.equals(student2));
        System.out.println(student1.hashCode()==student2.hashCode());
    }
    private String name;
    private String sex;

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

    @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) && Objects.equals(sex, student.sex);
    }

    @Override
    public int hashCode() {
        return 100;
    }
}
false
true

3.两个对象的hashcode相等,两个对象不一定相等。

我们看1和2的结果知道hashcode都相等但是两个对象不一定相等。

4.两个对象的hashcode不等,两个对象一定不等。

public class Student {
    public static void main(String[] args) {
        Student student1= new Student("wlf", "man");
        Student student2 = new Student("wf", "man");
        System.out.println(student1.equals(student2));
        System.out.println(student1.hashCode()==student2.hashCode());
    }
    private String name;
    private String sex;

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

    @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) && Objects.equals(sex, student.sex);
    }

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

以上我们都是即重写equals又重写hashcode。

为什么重写equals方法一定要重写hashcode

现在有两个Student对象:

  Student student1= new Student("wlf", "man");
  Student student2 = new Student("wlf", "man");

此时s1.equals(s2)一定返回true

假如只重写equals而不重写hashcode,那么Student类的hashcode方法就是Object默认的hashcode方法,由于默认的hashcode方法是根据对象的内存地址经哈希算法得来的,显然此时s1!=s2,故两者的hashcode不一定相等。
然而重写了equals,且s1.equals(s2)返回true,根据hashcode的规则,两个对象相等其哈希值一定相等,所以矛盾就产生了,因此重写equals一定要重写hashcode,而且从Student类重写后的hashcode方法中可以看出,重写后返回的新的哈希值与Student的两个属性有关。

我们来看看重写后的hash算法

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

Objects

public static int hash(Object... values) {
      return Arrays.hashCode(values);
  }

Arrays

public static int hashCode(Object a[]) {
        if (a == null)
            return 0;

        int result = 1;

        for (Object element : a)
            result = 31 * result + 
            (element == null ? 0 : element.hashCode());

        return result;
    }
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

活跃的咸鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值