在java中为什么重写equals要重写hashcode

 为什么重写equals要重写hashcode

在Java中,当我们重写equals方法时,通常也需要重写hashCode方法。这是因为:

  1. 一致性:如果两个对象相等(即equals方法返回true),那么它们的哈希码(hashCode)也应该相等。这是哈希表(如HashMap、HashSet等)的基本要求,以确保哈希表的正确性和性能。

  2. 提高哈希表的性能:当equals方法被重写后,如果不同时重写hashCode方法,那么哈希表中可能会出现大量哈希冲突,导致哈希表的性能下降。通过同时重写hashCode方法,可以降低哈希冲突的概率,从而提高哈希表的性能。

  3. 遵循Java规范:根据Java的约定,如果一个类重写了equals方法,那么它也应该重写hashCode方法。这样做有助于提高代码的可读性和可维护性。

代码示例 

接下来使用set去重来解释为什么重写equels要重写hashcode

这是没写equels和hashcode的代码

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class Main {


    public static void main(String[] args) {
        Student[] students = new Student[6];
        students[0]=new Student("zhangsan",18,1001);
        students[1]=new Student("lisi",17,1009);
        students[2]=new Student("wangwu",28,1006);
        students[3]=new Student("liuliu",19,1004);
        students[4]=new Student("zhaoqi",15,1005);
        students[5]=new Student("zhaoqi",15,1005);

        Set set = new HashSet(Arrays.asList(students));
        for (int i = 0; i < students.length; i++) {
            set.add(students[i]);
        }
        System.out.println(set);
    }

}
class Student {
    String name;
    int age;
    int no;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", no=" + no +
                '}';
    }

}

 让我们来看运行结果

可以看出来有两个zhaoqi,set的去重并不能将他去掉 

接下来我们看写了equals方法没写hashcode方法的运行截图 

 可以看出来有两个zhaoqi,set的去重依旧不能将他去掉 

 接下来我们看写了hashcode方法没写equals方法的运行截图 

只重写了hashcode没重写也不能成功去重

最后我们看equals和hashcode都重写的情况

[Student{name='liuliu', age=19, no=1004}, Student{name='wangwu', age=28, no=1006}, Student{name='zhangsan', age=18, no=1001}, Student{name='lisi', age=17, no=1009}, Student{name='zhaoqi', age=15, no=1005}]

最后结果成功去重了 

 重写equals和hashcode示例

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

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

什么是 hashcode(哈希码、散列码)?

想解决这个问题,要先知道什么是hashcode。hashCode是jdk根据对象的地址或者字符串或者数字算出来的 int 类型的数值,

hashcode 在 Object 的方法中源码是这样的:

public native int hashCode();

从源码可以看出,Object 中的 hashCode 调用了一个(native)本地方法,返回了一个 int 类型的整数,当然,这个整数可能是正数也可能是负数。

为什么 equals() 方法要重写?

默认情况下,Java中的 equals() 比较的是对象的引用。

equals 方法在 Object 下的实现源码如下:

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


 由此可见,相同的对象使用 equals() 进行比较结果会是 false ,这样就没有了比较的意义,所以要重写 equals 方法。

hashCode() 与 equals() 的关系

来了解一下 hashcode() 和 equals() 的关系:

1. 如果两个对象相等(equals 返回 true),则 hashcode 一定也是相同的

2. 如果两个对象不同(equals 返回 false),那么他们的 hashCode 值可能相同、可能不同

3. 如果两个对象的 hashcode 值相同(哈希冲突),那么它们可能相同、可能不同(equals 返回 true 或者返回 false)

4. 如果两个对象的 hashCode 值不同,那么它们一定不同(equals 返回 false)

equals() hashcode()
true(确定) true
false(确定) true / false
true / false true(确定)
false false(确实)


hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。
 

重写equals方法为什么还要重写hashcode方法?

回归根本问题:为什么两个方法都要重写。这种情况通常发生在 set 集合去重,我们都知道 set 集合是用来保存不同对象的集合,也就是说 set 集合内没有重复的元素。但有时,set集合会出现“异常”,即没有进行去重操作。

原因就是:只重写了 equals 方法,但没有重写 hashCode 方法。具体分析一下,只重写equals方法,那么 set 进行去重操作时,先判断的是两个对象的 hashcode 是否相等,由于没有重写hashcode() 方法,所以执行的是 Object 类下的hashcode() 方法,此时比较的实际上是两个相同对象的不同引用地址,所以结果出现了 false ,导致 equals 方法不用执行下去,也返回了 false 结果,最后结论就变成了两个明明相同的对象比较的结果是不同的,于是set集合中就插入了两个相同的对象。
 

总结 

  • equals() 方法用于比较两个对象是否相等,而 hashCode() 方法用于获取对象的哈希码

  • 在 Java 中,如果两个对象通过 equals() 方法判断为相等,则它们的 hashCode() 方法必须返回相同的值。这是因为在使用哈希表(如 HashMap、HashSet)等数据结构时,会先根据对象的哈希码确定存储位置,然后再使用 equals() 方法进行比较来确保唯一性。

  • 如果重写了 equals() 方法但没有重写 hashCode() 方法,那么可能会导致以下问题:

    • 当将对象放入哈希表中时,由于 hashCode() 返回的不是相同的值,哈希表无法正确定位到该对象所在的位置,从而无法正常操作该对象。

    • 当使用哈希集合(如 HashSet)时,由于 hashCode() 返回的不是相同的值,哈希集合无法正确判断两个对象是否相等,从而可能导致重复元素的存在。

  • 因此,在重写 equals() 方法时,必须同时重写 hashCode() 方法,以保证对象的相等性和哈希码的一致性

你可能感兴趣的:(Java,java,哈希算法,散列表)