Как проверить, равны ли два объекта в Java

JavaJavaBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом практическом занятии (лабораторной работе) вы научитесь проверять, равны ли два объекта в Java. Мы рассмотрим фундаментальное различие между использованием оператора == и метода equals() для сравнения объектов.

Вы начнете с использования встроенного метода equals() для сравнения объектов и поймете его поведение с разными типами данных. Затем вы узнаете, как переопределить метод equals() в своих собственных пользовательских классах, чтобы определить, что представляет собой логическое равенство для ваших объектов. Наконец, вы рассмотрите важный аспект - обработку нулевых (null) объектов при выполнении проверок на равенство, чтобы избежать потенциальных ошибок NullPointerException.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL java(("Java")) -.-> java/StringManipulationGroup(["String Manipulation"]) java(("Java")) -.-> java/ProgrammingTechniquesGroup(["Programming Techniques"]) java(("Java")) -.-> java/ObjectOrientedandAdvancedConceptsGroup(["Object-Oriented and Advanced Concepts"]) java(("Java")) -.-> java/SystemandDataProcessingGroup(["System and Data Processing"]) 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 и нажав Enter.

  2. Создайте новый файл с именем EqualityDemo.java в директории ~/project. Вы можете сделать это, щелкнув правой кнопкой мыши в проводнике файлов слева и выбрав "New File", а затем введя 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, str1 и str2, с одинаковым содержимым ("hello"), но используя new String(), что создает отдельные объекты в памяти.
    • Мы создаем третью ссылку на объект String, str3, и делаем ее указывающей на тот же объект, что и str1.
    • Мы используем как ==, так и equals() для сравнения str1 и str2, а также str1 и str3.
    • Мы также показываем сравнение примитивных типов int с использованием ==. Помните, что equals() используется для объектов, а не для примитивных типов.
  4. Сохраните файл EqualityDemo.java (Ctrl+S или Cmd+S).

  5. Откройте терминал внизу WebIDE.

  6. Скомпилируйте Java-программу, введя следующую команду и нажав Enter:

    javac EqualityDemo.java

    Если нет ошибок, вы не должны увидеть никакого вывода.

  7. Запустите скомпилированную программу, введя следующую команду и нажав Enter:

    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, потому что метод equals() класса String переопределен для сравнения фактического содержимого строк. str1 == str3 равно true, потому что str3 указывает на один и тот же объект, что и str1.

Это демонстрирует ключевое различие между == (равенство ссылок) и equals() (логическое равенство) при сравнении объектов в Java. Для примитивных типов == используется для сравнения значений.

Переопределение метода equals() в пользовательском классе

На предыдущем этапе мы увидели, как работает метод equals() для объектов класса String. Класс String уже переопределил стандартный метод equals() (наследованный от класса Object), чтобы обеспечить осмысленное сравнение на основе содержимого.

Однако, когда вы создаете свои собственные пользовательские классы, стандартный метод equals(), унаследованный от Object, просто использует оператор ==, то есть он проверяет только равенство ссылок. Чтобы сравнивать объекты вашего пользовательского класса на основе их атрибутов (логическое равенство), вам нужно переопределить метод equals() самостоятельно.

На этом этапе мы создадим простой класс Person и переопределим его метод equals().

  1. Убедитесь, что вы находитесь в директории ~/project в WebIDE.

  2. Создайте новый файл с именем Person.java в директории ~/project.

  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 (тип String) и age (тип int).
    • У нас есть конструктор для инициализации этих атрибутов.
    • У нас есть методы-геттеры для доступа к атрибутам.
    • Мы переопределили метод equals(). Рассмотрим шаги внутри переопределенного метода equals():
      • if (this == obj): Это оптимизация. Если две ссылки указывают на один и тот же объект, они определенно равны.
      • if (obj == null || getClass() != obj.getClass()): Это проверяет, является ли сравниваемый объект нулевым (null) или не является ли он экземпляром класса Person. Если хотя бы одно из условий истинно, они не могут быть равны.
      • Person person = (Person) obj;: Мы приводим общий объект типа Object к объекту типа Person, чтобы иметь доступ к его атрибутам name и age.
      • return age == person.age && name.equals(person.name);: Это ядро логического сравнения. Мы проверяем, совпадает ли age (используя == для примитивного типа int) и совпадает ли name (используя equals() для объектов типа String).
  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.class и PersonEqualityDemo.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 == person2 равно false, потому что они являются разными объектами, но person1.equals(person2) равно true, потому что их name и age совпадают в соответствии с нашим переопределенным методом. Объекты person1 и person3 не равны ни по одному из сравнений. Объекты person1 и person4 равны по обоим сравнениям, потому что они ссылаются на один и тот же объект.

Переопределяя метод equals(), вы определяете, что означает "равенство" для объектов вашего пользовательского класса на основе их логического состояния, а не только их местоположения в памяти.

Обработка нулевых (null) объектов при проверке равенства

На предыдущем этапе мы успешно переопределили метод equals() в классе Person для сравнения объектов на основе их атрибутов. Одним из важных аспектов написания надежных методов equals() является обработка возможных значений null. Если вы попытаетесь вызвать метод для объекта, имеющего значение null, это приведет к ошибке NullPointerException, которая является распространенной ошибкой в Java.

Наше переопределенный метод equals() в файле Person.java уже содержит проверку на null: if (obj == null || getClass() != obj.getClass()). Это стандартный способ обработки случая, когда сравниваемый объект имеет значение null.

На этом этапе мы продемонстрируем, что происходит при сравнении объекта с null и убедимся, что наш метод equals() обрабатывает это правильно.

  1. Убедитесь, что вы находитесь в директории ~/project в WebIDE.

  2. Откройте файл PersonEqualityDemo.java, который вы создали на предыдущем этапе.

  3. Добавьте следующие строки в метод main после существующих операторов сравнения:

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

    Этот код просто добавляет сравнение объекта person1 с null.

  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. Это происходит потому, что строка if (obj == null || getClass() != obj.getClass()) в методе equals() нашего класса Person проверяет на null перед попыткой доступа к любым атрибутам объекта obj.

Обработка значений null является важной частью написания надежного кода на Java, особенно при работе с сравнением объектов. Всегда включайте проверку на null в начале переопределенного метода equals().

Резюме

В этом практическом занятии (лабораторной работе) мы научились проверять, равны ли два объекта в Java. Мы начали с понимания различия между оператором ==, который проверяет равенство ссылок, и методом equals(), который проверяет логическое равенство. Мы продемонстрировали это на примерах с объектами класса String и примитивными типами, наблюдая, как == ведет себя по - другому, чем equals() для объектов.

Затем мы изучили, как переопределить метод equals() в пользовательских классах, чтобы определить свои собственные критерии равенства объектов. Это важно для того, чтобы наши пользовательские объекты сравнивались на основе их содержимого или состояния, а не только на основе их местоположения в памяти. Наконец, мы узнали о важности обработки нулевых (null) объектов в методе equals() для предотвращения ошибки NullPointerException и обеспечения надежных проверок на равенство.