Аннотация @EqualsAndHashCode
, использующая атрибут Long, такой как pk
, может привести к непредвиденному поведению при использовании со структурой на основе хеша (например, HashSet).
например.:
<strong i="9">@Entity</strong>
@EqualsAndHashCode(of = "pk")
class Foo {
<strong i="10">@Id</strong>
private Long pk;
private LocalDate createdAt;
}
<strong i="13">@Entity</strong>
class Foo {
<strong i="14">@Id</strong>
private Long pk;
private LocalDate createdAt;
public int hashCode() {
int PRIME = true;
int result = 1;
Object $pk = this.getPk();
int result = result * 59 + ($pk == null ? 43 : $pk.hashCode());
return result;
}
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
}
Поэтому, когда экземпляр с pk = null и другой с pk = 43, он вернет один и тот же хэш-код, и его можно будет считать одинаковым в структуре на основе хэша, а это не так.
И в случае использования OmniFaces ListConverter, который использует toString
, у нас возникает та же проблема.
Возможно, вернуть хэш-код экземпляра объекта, а не жестко заданную константу
Вы уже использовали этот сценарий или знаете какой-то способ обойти эту ситуацию?!
Информация о версии
Поэтому, когда экземпляр с pk = null и другой с pk = 43, он вернет тот же хэш-код.
Это не имеет значения. Более того, всегда будут коллизии хешей, независимо от того, что вы выберете.
Обратите внимание, что Arrays.hashCode
, String.hashCode
и многие другие производят множество столкновений, что совершенно бессмысленно.
Возможно, вернуть хэш-код экземпляра объекта, а не жестко заданную константу
В моем коде, написанном вручную, я утверждаю, что он не вызывается до того, как будет назначено значение id
. Это, конечно, странно, но таковы все альтернативы.
В этом случае можно было бы создать параметр аннотации, который мог бы указать, какое значение следует использовать, когда ПК имеет значение null. По умолчанию 43.
Это дало бы больше контроля разработчику.
@EqualsAndHashCode(of = "pk", ifAnyNull = -1)
Таким образом, он будет использовать -1 вместо 43 для любого поля, которое было нулевым.
43, вероятно, так же хорошо, как и любое другое число, и лучше, чем -1, 0 и 1. Если сделать его настраиваемым, это увеличит нагрузку на техническое обслуживание при очень низкой добавленной стоимости.
Использование хэш-кода Identity для null нарушит контракт equals.
Самый полезный комментарий
43, вероятно, так же хорошо, как и любое другое число, и лучше, чем -1, 0 и 1. Если сделать его настраиваемым, это увеличит нагрузку на техническое обслуживание при очень низкой добавленной стоимости.
Использование хэш-кода Identity для null нарушит контракт equals.