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

Posted 活跃的咸鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么重写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;
    }

以上是关于为什么重写equals方法一定要重写hashcode的主要内容,如果未能解决你的问题,请参考以下文章

JavaSE——为什么重写equals的同时一定要重写hashCode?

JavaSE——为什么重写equals的同时一定要重写hashCode?

关于object类的两个重要方法以及为什么重写equals一定要重写hashcode()

面试官:重写 equals 时为什么一定要重写 hashCode?

面试官:重写 equals 时为什么一定要重写 hashCode?

java中重写Object类的equals方法为啥要重写hashcode方法?不重写可以吗?