Menu
Coddy logo textTech

equals() и hashCode()

Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 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 имеют одинаковые name и age, они будут считаться равными и будут генерировать идентичные хеш-коды, что обеспечивает согласованное поведение в коллекциях.

challenge icon

Задание

Легко

Давайте создадим систему учета студентов, которая правильно реализует равенство объектов. Вы создадите класс Student, в котором два студента считаются равными, если у них одинаковый идентификатор студента и имя — независимо от того, являются ли они одним и тем же объектом в памяти.

Вы организуете свой код в двух файлах:

  • Student.java: Создайте класс, представляющий студента с тремя приватными полями: studentId (String), name (String) и gpa (double). Включите конструктор для инициализации всех полей и методы-геттеры для каждого поля.

    Переопределите метод equals() так, чтобы два объекта Student считались равными, если у них одинаковый studentId И одинаковое name. Следуйте стандартному шаблону: проверьте на идентичность ссылок, проверьте на null и тип, затем сравните соответствующие поля.

    Переопределите метод hashCode(), используя Objects.hash() с теми же полями, которые использовались в equals(). Не забудьте импортировать java.util.Objects в начале вашего файла.

  • Main.java: Оживите ваш класс Student, сравнивая объекты студентов. Вы получите шесть входных данных, представляющих двух студентов: ID, имя и GPA первого студента, а затем ID, имя и GPA второго студента.

    Создайте оба объекта Student, затем выполните три сравнения и выведите результаты:

    1. Выведите Same reference: , а затем результат проверки, равен ли первый студент самому себе (всегда должно быть true)
    2. Выведите Content equality: , а затем результат проверки, равен ли первый студент второму (на основе вашей реализации equals)
    3. Выведите Hash codes match: , а затем результат проверки, совпадают ли хэш-коды обоих студентов

Вы получите шесть входных данных: ID первого студента (String), имя первого студента (String), GPA первого студента (double), ID второго студента (String), имя второго студента (String) и GPA второго студента (double).

Обратите внимание, что когда у двух студентов совпадают ID и имена, и equals() возвращает true, И их хэш-коды совпадают — это контракт, который вы должны соблюдать!

Шпаргалка

Оператор == проверяет, указывают ли две ссылки на одну и ту же область памяти, а не имеют ли объекты одинаковое содержимое.

Чтобы сравнить содержимое объектов, переопределите метод equals(), следуя этому шаблону:

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;  // Та же ссылка
    if (obj == null || getClass() != obj.getClass()) return false;  // Null или другой тип
    Person person = (Person) obj;  // Приведение к нужному типу
    return age == person.age && name.equals(person.name);  // Сравнение полей
}

Всякий раз, когда вы переопределяете equals(), вы также должны переопределить hashCode(). Это контракт Java: равные объекты должны иметь одинаковый хэш-код.

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

Используйте Objects.hash() с теми же полями, которые используются в equals(). Это гарантирует правильную работу хэш-коллекций, таких как HashMap и HashSet.

Попробуйте сами

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Проверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование