使用 Long 属性(例如pk
)的@EqualsAndHashCode
注释在与基于散列的结构(例如 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 的实例时,它将返回相同的哈希码,并且在基于哈希的结构上可能被认为是相同的,但事实并非如此。
在使用toString
的 OmniFaces ListConverter 的情况下,我们遇到了同样的问题。
可能返回对象实例的哈希码而不是硬编码常量
您是否已经采取了这种情况,或者您知道解决这种情况的方法吗?!
版本信息
因此,当 pk = null 和其他 pk = 43 的实例时,它将返回相同的哈希码
这没关系。 此外,无论您选择什么,总会有哈希冲突。
请注意, Arrays.hashCode
、 String.hashCode
和许多其他的会产生大量的碰撞,而不是不必要的。
可能返回对象实例的哈希码而不是硬编码常量
在我手动编写的代码中,我断言在分配id
之前不会调用它。 这肯定很奇怪,但所有替代方案也是如此。
在这种情况下,可以创建一个注释参数,该参数可以告诉当 PK 为空时应该使用哪个值。 默认为 43。
这将为开发人员提供更多控制权。
@EqualsAndHashCode(of = "pk", ifAnyNull = -1)
因此,对于任何为空的字段,它将使用 -1 而不是 43
43 可能与任何其他数字一样好,并且优于 -1、0 和 1。使其可配置会增加维护负担,但附加值非常低。
对 null 使用 Identity 哈希码会破坏 equals 合约。
最有用的评论
43 可能与任何其他数字一样好,并且优于 -1、0 和 1。使其可配置会增加维护负担,但附加值非常低。
对 null 使用 Identity 哈希码会破坏 equals 合约。