Menu
CoddyTech

equals() 和 hashCode()

本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 42 课,共 87 课。

在 Java 中比较对象时,== 运算符会检查两个引用是否指向同一个内存位置。要比较对象的实际内容,你需要重写 equals() 方法。

public class Person {
    private String name;
    private int 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);
    }
}

equals() 方法遵循一个标准模式:先检查是否是同一个对象,然后验证类型,最后比较相关字段。

每当你重写 equals() 时,也必须重写 hashCode()。这是 Java 中的一项约定:相等的对象必须具有相同的哈希码。基于哈希的集合(如 HashMap 和 HashSet)依赖这条规则才能正常运行。

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

Objects.hash() 工具方法会根据与 equals() 相同的字段生成哈希码。如果两个 Person 对象的姓名和年龄相同,它们就会被视为相等,并生成相同的哈希码,从而确保它们在集合中的行为一致。

challenge icon

挑战

简单

让我们构建一个能正确实现对象相等性判断的学生记录系统。你将创建一个 Student 类,当两个学生的学生 ID 和姓名相同时,就认为他们相等,无论他们在内存中是否是同一个对象。

你需要将代码分成两个文件:

  • Student.java:创建一个表示学生的类,包含三个私有字段:studentId(String)、name(String)和 gpa(double)。添加一个用于初始化所有字段的构造函数,以及每个字段对应的 getter 方法。

    重写 equals() 方法,使两个 Student 对象在 studentId 相同且 name 相同时被视为相等。遵循标准模式:检查是否为同一个引用,检查是否为 null 以及类型是否相同,然后比较相关字段。

    使用 Objects.hash() 重写 hashCode() 方法,并使用与 equals() 中相同的字段。记得在文件顶部导入 java.util.Objects。

  • Main.java:通过比较学生对象,让你的 Student 类发挥作用。你会收到 6 个输入,分别表示两名学生的信息:第一名学生的 ID、姓名和 GPA,然后是第二名学生的 ID、姓名和 GPA。

    创建两个 Student 对象,然后进行三次比较并打印结果:

    1. 打印 Same reference: ,后面接第一名学生是否等于自身(结果应始终为 true)
    2. 打印 Content equality: ,后面接第一名学生是否等于第二名学生(根据你的 equals 实现判断)
    3. 打印 Hash codes match: ,后面接两名学生的哈希码是否相同

你会收到 6 个输入:第一名学生的 ID(String)、第一名学生的姓名(String)、第一名学生的 GPA(double)、第二名学生的 ID(String)、第二名学生的姓名(String),以及第二名学生的 GPA(double)。

注意,当两名学生的 ID 和姓名相同时,equals() 会返回 true,而且他们的哈希码也相同。这就是你必须遵守的约定!

亲手试试

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取第一个学生的数据
        String id1 = scanner.nextLine();
        String name1 = scanner.nextLine();
        double gpa1 = scanner.nextDouble();
        scanner.nextLine(); // 读取并丢弃换行符
        
        // 读取第二个学生的数据
        String id2 = scanner.nextLine();
        String name2 = scanner.nextLine();
        double gpa2 = scanner.nextDouble();
        
        // TODO: 使用输入数据创建两个 Student 对象
        
        // TODO: 输出 "Same reference: ",然后输出 student1 是否等于自身
        
        // TODO: 输出 "Content equality: ",然后输出 student1 是否等于 student2
        
        // TODO: 输出 "Hash codes match: ",然后输出两个学生的哈希码是否相同
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Java 在线编译器