Введение
В этом практическом занятии (лабораторной работе) вы научитесь проверять, равны ли два объекта в Java. Мы рассмотрим фундаментальное различие между использованием оператора == и метода equals() для сравнения объектов.
Вы начнете с использования встроенного метода equals() для сравнения объектов и поймете его поведение с разными типами данных. Затем вы узнаете, как переопределить метод equals() в своих собственных пользовательских классах, чтобы определить, что представляет собой логическое равенство для ваших объектов. Наконец, вы рассмотрите важный аспект - обработку нулевых (null) объектов при выполнении проверок на равенство, чтобы избежать потенциальных ошибок NullPointerException.
Использование метода equals() для проверки равенства
На этом этапе мы рассмотрим, как сравнивать объекты в Java с использованием метода equals(). В то время как оператор == проверяет, указывают ли два ссылочных объекта на один и тот же объект в памяти, метод equals() предназначен для проверки логического равенства двух объектов, то есть того, представляют ли они одно и то же значение или состояние.
Начнем с создания простого Java-файла, чтобы продемонстрировать этот концепт.
Откройте WebIDE и убедитесь, что вы находитесь в директории
~/project. Вы можете это проверить, посмотрев на приглашение в терминале или введяpwdи нажав Enter.Создайте новый файл с именем
EqualityDemo.javaв директории~/project. Вы можете сделать это, щелкнув правой кнопкой мыши в проводнике файлов слева и выбрав "New File", а затем введяEqualityDemo.java.Откройте файл
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()используется для объектов, а не для примитивных типов.
- Мы создаем два объекта
Сохраните файл
EqualityDemo.java(Ctrl+S или Cmd+S).Откройте терминал внизу WebIDE.
Скомпилируйте Java-программу, введя следующую команду и нажав Enter:
javac EqualityDemo.javaЕсли нет ошибок, вы не должны увидеть никакого вывода.
Запустите скомпилированную программу, введя следующую команду и нажав 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().
Убедитесь, что вы находитесь в директории
~/projectв WebIDE.Создайте новый файл с именем
Person.javaв директории~/project.Откройте файл
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).
- У нас есть два приватных атрибута:
Сохраните файл
Person.java.Теперь создадим еще один файл,
PersonEqualityDemo.java, чтобы протестировать наш переопределенный методequals(). Создайте этот файл в директории~/project.Откройте файл
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().Сохраните файл
PersonEqualityDemo.java.Откройте терминал. Убедитесь, что вы находитесь в директории
~/project.Скомпилируйте оба Java-файла. Вы можете скомпилировать несколько файлов сразу:
javac Person.java PersonEqualityDemo.javaЭто должно создать файлы
Person.classиPersonEqualityDemo.class.Запустите демонстрационную программу:
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(), вы определяете, что означает "равенство" для объектов вашего пользовательского класса на основе их логического состояния, а не только их местоположения в памяти.
Обработка нулевых объектов при проверке равенства
На предыдущем этапе мы успешно переопределили метод equals() в классе Person для сравнения объектов на основе их атрибутов. Одним из важных аспектов написания надежных методов equals() является обработка возможных значений null. Если вы попытаетесь вызвать метод для объекта, имеющего значение null, это приведет к ошибке NullPointerException, которая является распространенной ошибкой в Java.
Наше переопределенный метод equals() в файле Person.java уже содержит проверку на null: if (obj == null || getClass() != obj.getClass()). Это стандартный способ обработки случая, когда сравниваемый объект имеет значение null.
На этом этапе мы продемонстрируем, что происходит при сравнении объекта с null и убедимся, что наш метод equals() обрабатывает это правильно.
Убедитесь, что вы находитесь в директории
~/projectв WebIDE.Откройте файл
PersonEqualityDemo.java, который вы создали на предыдущем этапе.Добавьте следующие строки в метод
mainпосле существующих операторов сравнения:System.out.println("\nComparing with null:"); System.out.println("person1.equals(null): " + person1.equals(null));Этот код просто добавляет сравнение объекта
person1сnull.Сохраните файл
PersonEqualityDemo.java.Откройте терминал. Убедитесь, что вы находитесь в директории
~/project.Скомпилируйте измененный файл
PersonEqualityDemo.java:javac PersonEqualityDemo.javaПомните, что вам нужно перекомпилировать только те файлы, которые вы изменили. Поскольку файл
Person.javaна этом этапе не был изменен, нам нужно скомпилировать толькоPersonEqualityDemo.java.Запустите скомпилированную программу:
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 и обеспечения надежных проверок на равенство.



