如何在 Java 中检查两个对象是否相等

JavaJavaBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在这个实验中,你将学习如何在 Java 中检查两个对象是否相等。我们将探讨使用 == 运算符和 equals() 方法进行对象比较的根本区别。

你将首先使用内置的 equals() 方法来比较对象,并了解它在不同数据类型下的行为。然后,你将学习如何在自己的自定义类中重写 equals() 方法,以定义你的对象的逻辑相等性。最后,你将处理在执行相等性检查时处理空对象的重要问题,以防止潜在的 NullPointerException 错误。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL java(("Java")) -.-> java/SystemandDataProcessingGroup(["System and Data Processing"]) java(("Java")) -.-> java/StringManipulationGroup(["String Manipulation"]) java(("Java")) -.-> java/ProgrammingTechniquesGroup(["Programming Techniques"]) java(("Java")) -.-> java/ObjectOrientedandAdvancedConceptsGroup(["Object-Oriented and Advanced Concepts"]) java/StringManipulationGroup -.-> java/strings("Strings") java/ProgrammingTechniquesGroup -.-> java/method_overriding("Method Overriding") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/classes_objects("Classes/Objects") java/SystemandDataProcessingGroup -.-> java/object_methods("Object Methods") subgraph Lab Skills java/strings -.-> lab-560013{{"如何在 Java 中检查两个对象是否相等"}} java/method_overriding -.-> lab-560013{{"如何在 Java 中检查两个对象是否相等"}} java/classes_objects -.-> lab-560013{{"如何在 Java 中检查两个对象是否相等"}} java/object_methods -.-> lab-560013{{"如何在 Java 中检查两个对象是否相等"}} end

使用 equals() 方法进行相等性比较

在这一步中,我们将探讨如何在 Java 中使用 equals() 方法来比较对象。== 运算符用于检查两个对象引用是否指向内存中的同一个对象,而 equals() 方法则用于检查两个对象在逻辑上是否相等,即它们是否表示相同的值或状态。

让我们通过创建一个简单的 Java 文件来演示这个概念。

  1. 打开 WebIDE,确保你位于 ~/project 目录下。你可以通过查看终端提示符或输入 pwd 并按回车键来确认。

  2. ~/project 目录下创建一个名为 EqualityDemo.java 的新文件。你可以通过在左侧的文件资源管理器中右键单击,选择“新建文件”,然后输入 EqualityDemo.java 来完成。

  3. 在编辑器中打开 EqualityDemo.java 文件,并粘贴以下代码:

    public class EqualityDemo {
        public static void main(String[] args) {
            String str1 = new String("hello");
            String str2 = new String("hello");
            String str3 = str1;
    
            System.out.println("Comparing String objects:");
            System.out.println("str1 == str2: " + (str1 == str2));
            System.out.println("str1.equals(str2): " + str1.equals(str2));
            System.out.println("str1 == str3: " + (str1 == str3));
            System.out.println("str1.equals(str3): " + str1.equals(str3));
    
            System.out.println("\nComparing primitive types (int):");
            int num1 = 10;
            int num2 = 10;
            System.out.println("num1 == num2: " + (num1 == num2));
        }
    }

    在这段代码中:

    • 我们创建了两个 String 对象 str1str2,它们具有相同的内容("hello"),但使用 new String() 创建,这会在内存中创建不同的对象。
    • 我们创建了第三个 String 引用 str3,并让它指向与 str1 相同的对象。
    • 我们同时使用 ==equals() 来比较 str1str2,以及 str1str3
    • 我们还展示了使用 == 对基本数据类型 int 进行比较。请记住,equals() 用于对象,而不是基本数据类型。
  4. 保存 EqualityDemo.java 文件(Ctrl+S 或 Cmd+S)。

  5. 打开 WebIDE 底部的终端。

  6. 输入以下命令并按回车键来编译 Java 程序:

    javac EqualityDemo.java

    如果没有错误,你应该看不到任何输出。

  7. 输入以下命令并按回车键来运行编译后的程序:

    java EqualityDemo

    你应该会看到类似于以下的输出:

    Comparing String objects:
    str1 == str2: false
    str1.equals(str2): true
    str1 == str3: true
    str1.equals(str3): true
    
    Comparing primitive types (int):
    num1 == num2: true

    注意,str1 == str2 的结果为 false,因为它们是内存中的不同对象,尽管它们的内容相同。然而,str1.equals(str2) 的结果为 true,因为 String 类的 equals() 方法被重写以比较字符串的实际内容。str1 == str3 的结果为 true,因为 str3 指向与 str1 完全相同的对象。

这展示了在 Java 中比较对象时 ==(引用相等性)和 equals()(逻辑相等性)之间的关键区别。对于基本数据类型,== 用于值的比较。

在自定义类中重写 equals() 方法

在上一步中,我们了解了 equals() 方法如何用于 String 对象。String 类已经重写了默认的 equals() 方法(继承自 Object 类),以便根据内容进行有意义的比较。

然而,当你创建自己的自定义类时,从 Object 类继承的默认 equals() 方法只是使用 == 运算符,这意味着它只检查引用是否相等。要根据自定义类对象的属性(逻辑相等性)来比较这些对象,你需要自己重写 equals() 方法。

在这一步中,我们将创建一个简单的 Person 类并重写其 equals() 方法。

  1. 确保你在 WebIDE 的 ~/project 目录中。

  2. ~/project 目录中创建一个名为 Person.java 的新文件。

  3. 打开 Person.java 并粘贴以下 Person 类的代码:

    public class Person {
        private String name;
        private int age;
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    
        // Default equals() method (inherited from Object) would only check reference equality
        // We need to override it to check for logical equality based on name and age
        @Override
        public boolean equals(Object obj) {
            // Step 1: Check if the objects are the same instance
            if (this == obj) {
                return true;
            }
    
            // Step 2: Check if the object is null or of a different class
            if (obj == null || getClass() != obj.getClass()) {
                return false;
            }
    
            // Step 3: Cast the object to the correct type
            Person person = (Person) obj;
    
            // Step 4: Compare the relevant attributes
            return age == person.age &&
                   name.equals(person.name); // Use equals() for String comparison
        }
    }

    在这个 Person 类中:

    • 我们有两个私有属性:name(字符串类型)和 age(整数类型)。
    • 我们有一个构造函数来初始化这些属性。
    • 我们有获取属性的 getter 方法。
    • 我们重写了 equals() 方法。让我们看看重写的 equals() 方法中的步骤:
      • if (this == obj):这是一种优化。如果两个引用指向同一个对象,它们肯定相等。
      • if (obj == null || getClass() != obj.getClass()):这会检查要比较的对象是否为 null 或者是否不是 Person 类的实例。如果其中任何一个条件为真,它们就不可能相等。
      • Person person = (Person) obj;:我们将通用的 Object 类型转换为 Person 对象,以便可以访问其 nameage 属性。
      • return age == person.age && name.equals(person.name);:这是逻辑比较的核心。我们检查 age 是否相同(对于基本整数类型使用 ==)以及 name 是否相同(对于 String 对象使用 equals())。
  4. 保存 Person.java 文件。

  5. 现在,让我们创建另一个文件 PersonEqualityDemo.java 来测试我们重写的 equals() 方法。在 ~/project 目录中创建这个文件。

  6. 打开 PersonEqualityDemo.java 并粘贴以下代码:

    public class PersonEqualityDemo {
        public static void main(String[] args) {
            Person person1 = new Person("Alice", 30);
            Person person2 = new Person("Alice", 30);
            Person person3 = new Person("Bob", 25);
            Person person4 = person1;
    
            System.out.println("Comparing Person objects:");
            System.out.println("person1 == person2: " + (person1 == person2));
            System.out.println("person1.equals(person2): " + person1.equals(person2));
            System.out.println("person1 == person3: " + (person1 == person3));
            System.out.println("person1.equals(person3): " + person1.equals(person3));
            System.out.println("person1 == person4: " + (person1 == person4));
            System.out.println("person1.equals(person4): " + person1.equals(person4));
        }
    }

    在这个演示类中,我们创建了几个 Person 对象,并使用 == 和我们重写的 equals() 方法对它们进行比较。

  7. 保存 PersonEqualityDemo.java 文件。

  8. 打开终端。确保你在 ~/project 目录中。

  9. 编译这两个 Java 文件。你可以一次编译多个文件:

    javac Person.java PersonEqualityDemo.java

    这应该会创建 Person.classPersonEqualityDemo.class 文件。

  10. 运行演示程序:

    java PersonEqualityDemo

    你应该会看到类似于以下的输出:

    Comparing Person objects:
    person1 == person2: false
    person1.equals(person2): true
    person1 == person3: false
    person1.equals(person3): false
    person1 == person4: true
    person1.equals(person4): true

    正如预期的那样,person1 == person2false,因为它们是不同的对象,但 person1.equals(person2)true,因为根据我们重写的方法,它们的 nameage 是相同的。person1person3 在两种比较方式下都不相等。person1person4 在两种比较方式下都相等,因为它们引用同一个对象。

通过重写 equals() 方法,你可以根据自定义类对象的逻辑状态而不仅仅是它们的内存位置来定义“相等”的含义。

在相等性比较中处理空对象

在上一步中,我们成功地在 Person 类中重写了 equals() 方法,以便根据对象的属性进行比较。编写健壮的 equals() 方法的一个关键方面是处理潜在的 null 值。如果你尝试在 null 对象上调用方法,将会导致 NullPointerException,这是 Java 中常见的错误。

我们在 Person.java 中重写的 equals() 方法已经包含了对 null 的检查:if (obj == null || getClass() != obj.getClass())。这是处理被比较对象为 null 情况的标准方法。

在这一步中,我们将演示将对象与 null 进行比较时会发生什么,并确认我们的 equals() 方法能够正确处理这种情况。

  1. 确保你在 WebIDE 的 ~/project 目录中。

  2. 打开你在上一步中创建的 PersonEqualityDemo.java 文件。

  3. main 方法中,在现有的比较语句之后添加以下代码行:

    System.out.println("\nComparing with null:");
    System.out.println("person1.equals(null): " + person1.equals(null));

    这段代码只是添加了 person1null 的比较。

  4. 保存 PersonEqualityDemo.java 文件。

  5. 打开终端。确保你在 ~/project 目录中。

  6. 编译修改后的 PersonEqualityDemo.java 文件:

    javac PersonEqualityDemo.java

    请记住,你只需要重新编译你修改过的文件。由于在这一步中 Person.java 没有被修改,我们只需要编译 PersonEqualityDemo.java

  7. 运行编译后的程序:

    java PersonEqualityDemo

    你现在应该会看到之前的输出,后面跟着与 null 的新比较结果:

    Comparing Person objects:
    person1 == person2: false
    person1.equals(person2): true
    person1 == person3: false
    person1.equals(person3): false
    person1 == person4: true
    person1.equals(person4): true
    
    Comparing with null:
    person1.equals(null): false

    输出 person1.equals(null): false 确认了我们重写的 equals() 方法能够正确处理与 null 的比较,并返回 false,而不会抛出 NullPointerException。这是因为在我们 Person 类的 equals() 方法中,if (obj == null || getClass() != obj.getClass()) 这一行在尝试访问 obj 的任何属性之前会先检查是否为 null

在 Java 中,处理 null 是编写健壮代码的关键部分,尤其是在处理对象比较时。始终在重写的 equals() 方法开头包含 null 检查。

总结

在这个实验中,我们学习了如何在 Java 中检查两个对象是否相等。我们首先了解了 == 运算符和 equals() 方法之间的区别,== 运算符用于检查引用是否相等,而 equals() 方法用于检查逻辑是否相等。我们通过 String 对象和基本数据类型演示了这一点,观察到 == 运算符和 equals() 方法在处理对象时的不同表现。

然后,我们探讨了如何在自定义类中重写 equals() 方法,以定义我们自己的对象相等性标准。这对于确保我们的自定义对象基于其内容或状态进行比较,而不仅仅是基于其内存位置进行比较至关重要。最后,我们了解了在 equals() 方法中处理空对象的重要性,以防止出现 NullPointerException 并确保进行健壮的相等性检查。