Java hashCode() и equals()

Методы hashCode() и equals() — базовые методы языка Java. На их основе работают коллекции. Оба эти метода объявлены в классе java.lang.Object. Дочерние классы могут, а в некоторых случаях даже должны переопределять их. Про эти методы я уже как-то писал, но нужно упомянуть об этом ещё раз.

Метод hashCode()

Объявление в классе Object:

Метод hashCode() возвращает число, которое является хеш-кодом объекта. Реализация по умолчанию в классе Object обычно возвращает адрес объекта, но это в спецификации Java это не закреплено, так что некоторые реализации Java-машин вполне могут возвращать что-нибудь другое.

Метод equals()

Объявление в классе Object:

Возвращает true, если obj равен этому объекту и false  в противном случае. Реализация по умолчанию в классе Object  просто сравнивает ссылки на объекты, то есть возвращает true  в том случае, если обе ссылки указывают на один и тот же объект.

Соглашение между реализациями hashCode() и equals()

В большинстве случаев реализации hashCode()  и equals(), которую ваши классы наследуют от Object вам не подойдёт, так как вам нужно, чтобы при вызове equals() сравнивались не ссылки на объекты, а значения полей объектов. Именно поэтому вам нужно будет переопределять equals() для тех классов, которые будут использоваться в качестве ключей коллекций Map и Set. При этом нужно иметь в виду, что при переопределении equals() нужно всегда переопределять hashCode()  так, чтобы сохранялись следующие соглашения:

  • Если x.equals(y)  возвращает true, то hashCode() у обоих экземпляров объектов должны возвращать одинаковые значения.
  • Но если x.hashCode() == y.hashCode(), то вовсе не обязательно, чтобы x.equals(y)  возвращало true, оно может возвращать как true, так и false.

Как писать hashCode() и equals()?

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

  • Генерация на чистом Java, как оно было раньше
  • Генерация с помощью библиотеки Apache Commons Lang.
  • Генерация с помощью класса java.util.Objects, который входит в состав Java 7. В классе java.util.Objects  есть специальные методы public static int hash(Object... values)public static boolean deepEquals(Object a, Object b) и public static boolean equals(Object a, Object b). Эти методы пришли в Java из библиотеки Guava. Методы с приставкой deep отличаются от обычных тем, что они заходят внутрь массивов и проходят по их элементам, об этом написано чуть ниже.
  • Генерация с помощью Guava, где есть методы, аналогичные методам из java.util.Objects.

Всегда имеет смысл посмотреть на сгенерированный IDE код для общего развития. Здесь прослеживается следующая связь:

  • Все реализации коллекций и Map-ов в Java имеют переопределённые методы hashCode() и equals(), которые пробегаются по своим элементам для получения результата.
  • Массивы в Java не переопределяют hashCode() и equals(). Они используют реализацию из класса Object, которая сравнивает ссылки. Поэтому при построении hashCode() нужно пользоваться статическими методами hashCode()  и deepHashCode() из класса java.util.Arrays. При написании методов equals нужно аналогично использовать методы equals()  и deepEquals() из класса java.util.Arrays. Методы с приставкой deep здесь отличаются от обычных тем, что в случае, если массив(ы) содержать в качестве элементов другие массивы, то методы без приставки deep будут возвращать значения, основанные на методе из Object, а с приставкой deep будут заходить внутрь этого вложенного массива и проходиться по его элементам.

P. S.

Пока писал эту статью понял, что в моём учебнике по Java не описаны методы класса Object. Странно. Как же я смог их пропустить? Надо как-то восполнить этот пробел.


Поделиться:

Java hashCode() и equals(): 1 комментарий

Добавить комментарий

Ваш e-mail не будет опубликован.

*