Hashcode java для чего нужен

Hashcode java для чего нужен

В классе Object, который является родительским классом для объектов java, определен метод hashCode(), позволяющий получить уникальный целый номер для данного объекта. Когда объект сохраняют в коллекции типа HashSet, то данный номер позволяет быстро определить его местонахождение в коллекции и извлечь. Функция hashCode() объекта Object возвращает целое число int, размер которого равен 4-м байтам и значение которого располагается в диапазоне от -2 147 483 648 до 2 147 483 647.

Рассмотрим простой пример HashCodeTest.java, который в консоли будет печатать значение hashCode.

Значение hashCode программы можно увидеть в консоли.

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

Функция сравнения объектов equals()

В родительском классе Object наряду с функцией hashCode() имеется еще и логическая функция equals(Object)/ Функция equals(Object) используется для проверки равенства двух объектов. Реализация данной функции по умолчанию просто проверяет по ссылкам два объекта на предмет их эквивалентности.

Рассмотрим пример сравнения двух однотипных объектов Test следующего вида :

Создадим 2 объекта типа Test с одинаковыми значениями и сравним объекты с использованием функции equals().

Результат выполнения программы будет выведен в консоль :

Не трудно было догадаться, что результат сравнения двух объектов вернет «false». На самом деле, это не совсем верно, поскольку объекты идентичны и в real time application метод должен вернуть true. Чтобы достигнуть этого корректного поведения, необходимо переопределить метод equals() объекта Test.

Вот теперь функция сравнения equals() возвращает значение «true». Достаточно ли этого? Попробуем добавить объекты в коллекцию HashSet и посмотрим, сколько объектов будет в коллекции? Для этого в в метод main примера EqualsExample добавим следующие строки :

Однако в коллекции у нас два объекта.

Поскольку Set содержит только уникальные объекты, то внутри HashSet должен быть только один экземпляр. Чтобы этого достичь, объекты должны возвращать одинаковый hashCode. То есть нам необходимо переопределить также функцию hashCode() вместе с equals().

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

Читайте также:  Eosinfo не видит камеру

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

Использование библиотеки commons-lang.jar для переопределения hashCode() и equals()

Процесс формирования методов hashCode() и equals() в IDE Eclipse автоматизирован. Для создания данных методов необходимо правой клавишей мыши вызвать контекстное меню класса (кликнуть на классе) и выбрать пункт меню Source (Class >> Source), в результате которого будет открыто следующее окно со списком меню для класса.

Выбираем пункт меню «Generate hachCode() and equals()» и в класс будут добавлены соответствующие методы.

Библиотека Apache Commons включает два вспомогательных класса HashCodeBuilder и EqualsBuilder для вызова методов hashCode() и equals(). Чтобы включить их в класс необходимо внести следующие изменения.

Примечание : желательно в методах hashCode() и equals() не использовать ссылки на поля, заменяйте их геттерами. Это связано с тем, что в некоторых технологиях java поля загружаются при помощи отложенной загрузки (lazy load) и не доступны, пока не вызваны их геттеры.

Скачать пример

Исходный код рассмотренного примера в виде проекта Eclipse можно скачать здесь (263 Kб).

Методы 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()?

В большинстве > 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 будут заходить внутрь этого вложенного массива и проходиться по его элементам.

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

Читайте также:  Разделить на слоги слово забота

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

Для решения задачи сравнения ссылочных переменных существует стандартное решение – метод equals(). Цель данного метода – определить идентичны ли объекты внутри, сравнив их внутреннее содержание. У класса Object есть своя реализация метода equals, которая просто сравнивает ссылки:

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

У метода equals() есть большой минус – он слишком медленно работает. Для этого был придуман метод hashCode(). Для каждого объекта данный метод возвращает определенное число. Какое именно – это тоже решает разработчик класса, как и в случае с методом equals().

Стандартная реализация метода hashCode() в классе Object:

Вместо того чтобы сравнивать объекты, будем сравнивать их hashCode, и только если hashCode-ы равны, сравнивать объекты посредством equals().

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

1) у двух разных объектов может быть одинаковый hashCode ;

2) у одинаковых объектов (с точки зрения equals()) должен быть одинаковый hashCode ;

3) хеш-коды должны быть выбраны таким образом, чтобы не было большого количества различных объектов с одинаковыми hashCode. Ситуация, когда у различных объектов хеш-коды совпадают называется коллизией.

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

Дело в том, что коллекции в Java перед тем как сравнить объекты с помощью equals всегда ищут/сравнивают их с помощью метода hashCode(). И если у одинаковых объектов будут разные hashCode, то объекты будут считаться разными — до сравнения с помощью equals() просто не дойдет.

Большинство современных IDE помогают переопределять методы equals() и hashCode(). К примеру, в Intellij Idea можно набрать комбинацию клавиш Alt+Ins, и в выпадающем меню Generate выбрать пункт equals and hashCode.

Ссылка на основную публикацию
Adblock
detector