Включите исполнение JavaScript в браузере, чтобы запустить приложение.
11 ноя 2024

Методы equals() и hashcode() в Java: отличия и примеры применения

Подробное руководство о методах сравнения equals() и hashcode() в Java. Отличия equals() и hashcode() и их спецификация. Когда необходимо применять equals() и hashcode(). Зачем необходимо переопределять методы equals() и hashcode() — читайте в нашей статье.

Программирование на Java построено на объектах. Их иногда приходится сравнивать друг с другом. Для этого служат методы equals() или hashCode(). Они взаимосвязаны и играют важную роль в сравнении объектов и реализации алгоритмов, основанных на хешировании. Расскажем о том, как они используются и чем отличаются друг от друга.

Метод equals() в Java

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

Для такого сравнения по смыслу разработчики должны переопределить в своих классах equals(). В уже переопределенном методе следует сравнивать значения полей объекта друг с другом. Так можно определить, являются ли они «равными» по смыслу. Например, чтобы сравнить данные двух людей на основе класса Person с полями name и age, нужно сравнить оба поля таблицы и определить, являются ли два имеющихся в ней объекта Person копиями данных одного и того же человека.

Спецификация equals()

Теперь поговорим подробнее об особенностях equals().

Рефлексивность

Одно из основных свойств метода. Означает равенство каждого объекта самому себе.

Рефлексивность нужна при переопределении классов. При нарушении этого правила возможны ошибки кода и логики программы: например, нерефлексивный объект будет удален из коллекции и признан неравным самому себе.

Симметричность

Еще одно важное свойство метода, гарантирующее взаимное сравнение объектов. Если a.equals(b) верно, b.equals(a) — тоже. Симметричность важнее всего для работы с коллекциями, где возможно сравнение объектов в разных направлениях.

Транзитивность

Свойство, гарантирующее последовательное сравнение объектов. При равенстве объекта A с B, а объекта B с C, A также должен быть равен C. С помощью транзитивности можно строить логические цепочки сравнений.

Согласованность

Свойство, гарантирующее неизменный результат при многократном вызове метода: если значения объектов не меняются, не меняется и результат операции. Согласованность equals() важна для обеспечения предсказуемости, стабильности работы программ, для защиты от случайных факторов.

Сравнение null

Бывают ситуации, когда один из сравниваемых объектов является null. По умолчанию, вызов equals() для null объекта приведет к ошибке NullPointerException. Во избежание этого при реализации equals() необходимо проверить оба объекта на null перед сравнением значений. Если любой из двух объектов является нулевым, то сразу возвращайте false: null не может быть равен ничему, включая себя. Только потом можно сравнивать значения полей объектов друг с другом. 

Когда применяют equals()

Этот метод применяется в тех случаях, когда приходится сравнивать объекты по содержанию, а не только по ссылке в памяти, например:

  • при добавлении в Set, HashSet или LinkedHashSet — для исключения дублирования элементов;
  • при проверке в List, ArrayList или LinkedList с помощью метода contains();
  • при поиске в Map, HashMap или LinkedHashMap с помощью метода containsKey();
  • при сравнении между собой в условиях if или switch, если принятие решения зависит от конкретного значения.

Метод hashcode() в Java

Метод hashCode() в Java нужен для генерации целочисленного значения, называемого хеш-кодом, для каждого объекта. Хеш-коды нужны для поиска объектов в структурах данных HashMap и HashSet. Для корректной работы кеширования нужно переопределить hashCode() в своих классах. Хеш-коды для равных между собой по equals() объектов должны быть равны, для неравных — неравны. Корректный hashCode() помогает эффективнее искать элементы в хеш-таблицах.

Отличие от equals

Несмотря на взаимосвязь, методы hashCode() и equals() решают разные задачи:

  • equals() проверяет объекты на равенство по содержанию, возвращая true при равенстве или false при неравенстве;
  • hashCode() генерирует целочисленный хеш-код объекта, чтобы найти его в хеш-таблицах.

Два равных по equals() объекта должны иметь одинаковый хеш-код. Но на практике иногда коды не совпадают. Чтобы проверять эти соответствия, используется hashCode().

Спецификация hashCode() 

Реализация hashCode() должна быть согласованной: любые многократные вызовы метода hashCode() к одному и тому же объекту всегда должны возвращать одно и то же значение кода, если его состояние не изменилось. 

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

Когда применяют hashcode() 

В основном метод hashCode() нужен в структурах данных, основанных на технологии хеширования: HashMap, HashSet, Hashtable. Хеш-коды нужны для быстрого определения позиции объекта в хеш-таблице. Они бывают удобны для сравнения нескольких объектов между собой, хотя эта функция не является основной.

Переопределение equals() и hashcode() 

Переопределение методов в Java необходимо для корректной работы с объектами в коллекциях и других структурах данных. Переопределяя equals(), разработчик может сравнивать элементы кода по их содержанию, а не только по ссылке в памяти. Переопределение hashCode() — гарантия единообразия кодов для объектов, равных по equals(). Если все эти методы будут корректно реализованы, операции с объектами в Java будут производиться без ошибок, и код заработает как надо.