为什么在 Java 中重写 equals 时需要重写 hashcode?

简介: 【8月更文挑战第22天】

在 Java 中,equals 方法用于比较两个对象的相等性,而 hashCode 方法用于生成对象的哈希码。这两个方法对于集合框架的正确功能至关重要,尤其是使用哈希表(例如 HashMapHashSet)时。

哈希表的工作原理

哈希表是一种数据结构,它使用哈希函数将键映射到数组索引。哈希函数将键转换为一个整数,该整数用作数组索引。哈希表使用此索引来快速检索和存储键值对。

equals 和 hashCode 的作用

为了让哈希表正常工作,equalshashCode 方法必须一起使用。

  • equals:用于比较两个键是否相等。如果两个键相等,则它们必须具有相同的哈希码。
  • hashCode:用于生成对象的哈希码。如果两个对象相等,则它们必须具有相同的哈希码。

重写 hashCode 的重要性

如果你重写了 equals 方法来比较两个对象的相等性,但没有重写 hashCode 方法,则可能会导致哈希表出现不一致的行为。这是因为:

  • 哈希表使用 hashCode 方法将键映射到数组索引。
  • 如果两个对象相等但具有不同的哈希码,则它们将被映射到哈希表中的不同索引。
  • 这将导致查找和插入操作出现问题,因为哈希表将无法找到或插入具有相同键但不同哈希码的对象。

示例

以下示例演示了不重写 hashCode 方法会导致的问题:

public class Person {
   

    private String name;

    // 重写 equals 方法
    @Override
    public boolean equals(Object o) {
   
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return name.equals(person.name);
    }

    // 未重写 hashCode 方法
}

public class Main {
   

    public static void main(String[] args) {
   
        Person person1 = new Person();
        person1.name = "John Doe";

        Person person2 = new Person();
        person2.name = "John Doe";

        // person1 和 person2 相等,但具有不同的哈希码
        System.out.println(person1.equals(person2)); // true
        System.out.println(person1.hashCode() == person2.hashCode()); // false

        // 将 person1 和 person2 添加到 HashSet 中
        HashSet<Person> set = new HashSet<>();
        set.add(person1);

        // 无法找到 person2,因为哈希表使用哈希码进行查找
        System.out.println(set.contains(person2)); // false
    }
}

在上面的示例中,Person 类重写了 equals 方法以比较两个 Person 对象的相等性。但是,它没有重写 hashCode 方法。因此,person1person2 具有相同的名称,但具有不同的哈希码。当将它们添加到 HashSet 中时,HashSet 无法找到 person2,因为它是使用哈希码进行查找的。

结论

在 Java 中,重写 equals 方法时需要重写 hashCode 方法,以确保哈希表和其他基于哈希的集合框架的正确功能。如果不重写 hashCode 方法,可能会导致不一致的行为和查找和插入操作出现问题。

目录
相关文章
|
存储 Java 开发者
Java 中的 equals 方法:看似简单,实则深藏玄机
本文深入探讨了Java中`equals`方法的设计与实现。默认情况下,`equals`仅比较对象引用是否相同。以`String`类为例,其重写了`equals`方法,通过引用判断、类型检查、长度对比及字符逐一比对,确保内容相等的逻辑。文章还强调了`equals`方法需遵循的五大原则(自反性、对称性等),以及与`hashCode`的关系,避免集合操作中的潜在问题。最后,对比了`instanceof`和`getClass()`在类型判断中的优劣,并总结了正确重写`equals`方法的重要性,帮助开发者提升代码质量。
813 1
|
存储 Java C++
java中“==”和equals,究竟比的是什么
java中“==”和equals,究竟比的是什么
243 4
|
存储 Java C++
java中“==”和equals,究竟比的是什么
java中“==”和equals,究竟比的是什么
188 3
java中“==”和equals,究竟比的是什么
|
Java 编译器
在Java中,关于final、static关键字与方法的重写和继承【易错点】
在Java中,关于final、static关键字与方法的重写和继承【易错点】
266 5
|
Java 编译器 数据安全/隐私保护
Java 重写(Override)与重载(Overload)详解
在 Java 中,重写(Override)和重载(Overload)是两个容易混淆但功能和实现方式明显不同的重要概念。重写是在子类中重新定义父类已有的方法,实现多态;重载是在同一类中定义多个同名但参数不同的方法,提供多种调用方式。重写要求方法签名相同且返回类型一致或为父类子类关系,而重载则关注方法参数的差异。理解两者的区别有助于更好地设计类和方法。
1235 2
|
Java
描述 Java 中的重载和重写
【8月更文挑战第22天】
147 0
【Java基础面试十八】、说一说重写与重载的区别
这篇文章阐述了Java中重写与重载的区别:重载是同一个类中方法名相同但参数列表不同的方法之间的关系,而重写是子类中方法与父类中相同方法名和参数列表的方法之间的关系,且子类的返回值应小于等于父类,访问修饰符应大于等于父类。
【Java基础面试十八】、说一说重写与重载的区别
|
Java 编译器
Java重写(Override)&重载(Overload)
重写(Override)概述 Java面向对象编程中的重写(override)指的是子类可以重写其父类中的非private方法,使得子类在调用该方法时会使用自己的实现而不是父类的实现。 重写(Override)讲解 定义一个名为 Animal 的父类和一个名为 Cat 的子类,其中 Cat 类继承了 Animal 类。Animal 类中有一个名为 move() 的方法,Cat 类可以对这个方法进行重写。 Animal 类中的 move() 方法不是private 类型,因此它可以被其子类重写。在 Cat 类中,使用相同的名称和参数列表来重新定义了 move() 方法,并且使用 @Overrid
461 0
|
Java 编译器
在 Java 中,重写(Override)和重载(Overload)是两种不同的概念,用于实现多态性。它们有着不同的作用和使用场景。
在 Java 中,重写(Override)和重载(Overload)是两种不同的概念,用于实现多态性。它们有着不同的作用和使用场景。
下一篇
开通oss服务