Переопределение метода hashCode() тесно связано с переопределением equals(): оба метода формируют базу для корректного использования объекта в коллекциях типа HashMap, HashSet, Hashtable и других структурах, опирающихся на сравнение и хеш-функции.
Правила:
equals(), обязательно переопределяйте и hashCode().equals(), должны вернуть одинаковый hashCode().Objects.hash() или IDE-шаблоны, во избежание ошибок.hashCode() должен возвращать одинаковое значение для одного и того же объекта на протяжении его "жизни" (если поля, участвующие в hashCode, неизменны).class User { private String name; public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof User)) return false; User user = (User) o; return Objects.equals(name, user.name); } public int hashCode() { return Objects.hash(name); } }
Вопрос: "Что случится, если два разных по equals() объекта вернут одинаковый hashCode()? Будет ли это ошибкой?"
Ответ: Нет, это не ошибка. Коллизии хэш-кодов разрешимы и ожидаемы — важно лишь, чтобы если объекты равны по equals, их hashCode был одинаков. Если разные по equals объекты дают одинаковый hashCode, коллекции будут работать медленнее (из-за большего числа коллизий), но корректно.
История
В финансовом ПО сравнивали проекты по нескольким полям, но переопределили только equals(). Хранили объекты в HashSet, возникали дубликаты, так как hashCode() не был переопределён и работал по умолчанию (различался для каждого экземпляра).
История
В системе складского учёта после добавления изменений бизнес-логики расширили equals(), но забыли обновить hashCode(). Объекты с разными hashCode, но equals=true, терялись в HashMap (не находились по ключу), приводя к большим финансовым ошибкам.
История
В веб-приложении использовали изменяемые поля в расчёте hashCode. При обновлении значения внутреннего поля хеш изменялся, и объект "терялся" для HashSet/HashMap: его невозможно было найти или удалить через стандартные методы, что вело к утечкам памяти и багам.