Случай toString()
отличается, вы можете делать все, что захотите, с помощью toString()
, поэтому я покрою только equals()
(и hashCode()
).
Во-первых, правило: , если вы хотите сохранить объект в List
, Map
или Set
, тогда требуется, чтобы equals
и hashCode
были реализованы , поэтому они подчиняются стандартному контракту, указанному в документации .
Теперь, как реализовать equals()
и hashCode()
? «Естественной» идеей было бы использовать свойства, отображаемые как Id
, как часть equals()
:
public class User {
...
public boolean equals(Object other) {
if (this==other) return true;
if (id==null) return false;
if ( !(other instanceof User) ) return false;
final User that = (User) other;
return this.id.equals( that.getId() );
}
public int hashCode() {
return id==null ? System.identityHashCode(this) : id.hashCode();
}
}
К сожалению, это решение имеет серьезную проблему : при использовании сгенерированных идентификаторов значения не присваиваются до тех пор, пока объект не станет постоянным , поэтому если переходный объект добавляется к Set
перед сохранением, его хеш-код будет изменяться, пока он находится в Set
, и это нарушает контракт Set
.
Таким образом, рекомендуется использовать атрибуты, которые являются частью бизнес-ключа , то есть комбинацию атрибутов, уникальных для каждого экземпляра с одинаковыми идентификационными данными базы данных. Например, для класса User это может быть имя пользователя:
public class User {
...
public boolean equals(Object other) {
if (this==other) return true;
if ( !(other instanceof User) ) return false;
final User that = (User) other;
return this.username.equals( that.getUsername() );
}
public int hashCode() {
return username.hashCode();
}
}
Справочная документация Hibernate обобщает это следующим образом:
" Никогда не используйте идентификатор базы данных для реализации равенства; используйте бизнес-ключ, комбинацию уникальных, обычно неизменяемых, атрибутов . Идентификатор базы данных изменится, если временный объект станет постоянным. Если временный Экземпляр (обычно вместе с отдельными экземплярами) хранится в Set
, изменение hashcode
нарушает контракт Set
. Атрибуты для бизнес-ключей не должны быть такими же стабильными, как первичные ключи базы данных, у вас есть только чтобы гарантировать стабильность, пока объекты находятся в одном наборе. " - 12.1.3. С учетом идентичности объекта
" Рекомендуется реализовать equals()
и hashCode()
, используя равенство бизнес-ключей . Равенство бизнес-ключей означает, что метод equals()
сравнивает только свойства, которые формируют бизнес-ключ. ключ, который идентифицирует наш экземпляр в реальном мире (естественный ключ-кандидат) "- 4.3. Реализация equals () и hashCode ()
Итак, вернемся к первоначальному вопросу:
- Используйте бизнес-ключ, если это возможно.
@Transient
атрибуты, скорее всего, не являются частью такого ключа.
- Если это невозможно, используйте свойства идентификатора, но не забудьте получить значения, назначенные ранее, чтобы добавить объект в
List
, Map
, Set
.
Смотри также