为什么重写 equals 时,必须重写 hashCode?

在 Java 中,当一个类重写了 equals 方法时,通常也需要重写 hashCode 方法。这是因为在使用哈希集合(如 HashSetHashMap 等)时,hashCode 方法的作用非常重要。

哈希集合通过哈希值(即 hashCode 方法返回的值)来确定元素在集合中的位置。当我们向哈希集合中添加元素时,集合会首先计算元素的哈希值,然后根据哈希值找到元素在集合中的位置。如果两个对象在 equals 方法中被认为是相等的,则它们必须具有相同的哈希值,以确保它们能够被正确地处理。

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

  1. 相等的对象具有不同的哈希值,这将违反哈希集合的约定,导致无法正确地查找和删除对象。
  2. 相等的对象可能被错误地视为不同的对象,因为它们的哈希值不同。

下面是一个简单的示例,展示了在重写 equals 方法时为什么也需要重写 hashCode 方法:

import java.util.HashMap;

class Person {
    private String name;
    private int age;

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

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        Person person = (Person) obj;
        return age == person.age &&
                name.equals(person.name);
    }

    // 没有重写 hashCode 方法

    public static void main(String[] args) {
        HashMap<Person, String> map = new HashMap<>();
        Person person1 = new Person("Alice", 30);
        Person person2 = new Person("Alice", 30);

        map.put(person1, "Person 1");
        map.put(person2, "Person 2");

        System.out.println(map.size()); // 输出:2,因为没有重写 hashCode 方法,导致两个相等的对象具有不同的哈希值,被认为是不同的对象
    }
}

在这个例子中,Person 类重写了 equals 方法来比较两个 Person 对象是否相等。然而,由于没有重写 hashCode 方法,导致两个相等的 Person 对象具有不同的哈希值,因此被哈希集合(HashMap)视为不同的对象,最终导致集合中包含了两个相等的对象。

要重写 hashCode 方法,可以根据 equals 方法中使用的字段来生成哈希值。通常情况下,可以将对象中每个用于比较相等性的字段的哈希值合并起来生成一个新的哈希值。以下是一个修复上面示例的方式:

import java.util.HashMap;

class Person {
    private String name;
    private int age;

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

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        Person person = (Person) obj;
        return age == person.age &&
                name.equals(person.name);
    }

    @Override
    public int hashCode() {
        return name.hashCode() + age; // 将 name 的哈希值和 age 相加
    }

    public static void main(String[] args) {
        HashMap<Person, String> map = new HashMap<>();
        Person person1 = new Person("Alice", 30);
        Person person2 = new Person("Alice", 30);

        map.put(person1, "Person 1");
        map.put(person2, "Person 2");

        System.out.println(map.size()); // 输出:1,重写了 hashCode 方法后,两个相等的对象具有相同的哈希值,被视为同一个对象
    }
}

在这个例子中,hashCode 方法使用了 name.hashCode()age 的值的相加来生成哈希值。这样,两个相等的 Person 对象将具有相同的哈希值,因此被哈希集合视为同一个对象。

相关推荐

  1. 为什么 equals 必须 hashCode

    2024-04-03 20:50:03       35 阅读
  2. 为什么 equals 必须 hashCode

    2024-04-03 20:50:03       22 阅读
  3. stream流中distinct方法equals相关

    2024-04-03 20:50:03       53 阅读
  4. 方法的原则

    2024-04-03 20:50:03       61 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-03 20:50:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-03 20:50:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-03 20:50:03       82 阅读
  4. Python语言-面向对象

    2024-04-03 20:50:03       91 阅读

热门阅读

  1. js绑定点击事件的方法

    2024-04-03 20:50:03       30 阅读
  2. 面试算法-128-单词拆分 II

    2024-04-03 20:50:03       41 阅读
  3. RabbitMQ

    2024-04-03 20:50:03       32 阅读
  4. Ceph常用命令总结

    2024-04-03 20:50:03       35 阅读
  5. 面试题多态结合线程

    2024-04-03 20:50:03       40 阅读