Ответ
Да, если переопределён equals, но реализация должна быть безопасной для жизненного цикла сущности.
Главная проблема: Поле id часто генерируется базой данных и равно null до сохранения сущности (transient state). Использование id в hashCode() нарушит контракт: хэш-код объекта изменится после сохранения, что сломает коллекции типа HashSet или HashMap.
Практические подходы:
-
Использовать константный
hashCode(наиболее безопасный для transient-сущностей).@Override public int hashCode() { return getClass().hashCode(); // Все экземпляры класса имеют один хэш-код }- Плюс: Безопасно для коллекций на всех этапах жизненного цикла.
- Минус: Снижает производительность
HashMap(все сущности попадают в одну корзину).
-
Использовать неизменяемое бизнес-поле (например, UUID, email), если оно гарантированно уникально и известно до сохранения.
@Override public int hashCode() { return Objects.hash(uniqueBusinessKey); // Например, uuid или email } -
Не переопределять
hashCode()вообще, если сущности не используются в хэш-коллекциях. Но это рискованно, если в будущем использование изменится.
Вывод: Константная реализация — самый надёжный вариант по умолчанию, так как гарантирует соблюдение контракта equals/hashCode при любом состоянии сущности.
Ответ 18+ 🔞
А, слушай, вот эта тема с hashCode для сущностей — это же классический пиздец, на котором все обжигаются! Ну, типа, вроде всё просто: переопределил equals — переопределяй и hashCode. Ан нет, сука, тут подвох ебаный!
Смотри, в чём прикол. Твой id — он же, блядь, как девственница до первой брачной ночи: null, пока в базу не запихнешь. А если ты в hashCode это поле id засунешь, то получается пиздец: объект до сохранения и после — это два разных хэша, ёпта! И вся твоя красивая HashMap или HashSet накрывается медным тазом, потому что контракт нарушен. Объект в коллекции был с одним хэшем, а после persist() у него хэш поменялся — и всё, пиши пропало, найти его уже не сможешь. Удивление пиздец!
Так что, варианты, конечно, есть, но они все — сплошной компромисс, блядь.
Вариант раз — константный hashCode.
Просто берёшь и возвращаешь хэш класса. Все сущности одного типа — один хэш на всех, как братья-близнецы.
@Override
public int hashCode() {
return getClass().hashCode(); // Все в одну кучу, блядь!
}
- Плюс: Безопасно на все сто, ебать. Не важно, сохранился объект или нет — хэш не меняется. Контракт в порядке, коллекции не сломаются.
- Минус: Производительность, сука, страдает. Все твои сущности в
HashMapбудут в одной корзине, и поиск превратится в линейный обход списка. Но, честно, для многих приложений это не критично, пока сущностей не овердохуища.
Вариант два — ключ бизнес-логики.
Если есть какое-то поле, которое уникально и известно ДО сохранения (типа uuid, email для пользователя), то можно по нему хэшировать.
@Override
public int hashCode() {
return Objects.hash(this.uuid); // Или this.email
}
Но это, блядь, надо быть уверенным, что это поле реально уникально и не null. А то опять пиздец.
Вариант три — не трогать вообще.
Можно оставить дефолтную реализацию от Object. Но это, блядь, как ходить по охуенно тонкому льду. Сегодня не используешь в хэш-коллекциях — всё ок. Завтра коллега добавит — и привет, неожиданные косяки. Доверия к такому решению — ноль ебать.
Так что же делать-то, блядь? А вывод, собственно, простой, хоть и не самый приятный. Константная реализация — это наш бронежилет. Да, производительность не идеальна, зато надёжно, ебать мои старые костыли! Гарантия, что контракт не нарушится ни при каких условиях. А с производительностью потом разберёшься, если реально станет проблемой. Главное — не выстрелить себе в ногу на ровном месте.