Lombok: 用于基于散列的结构时,空属性上的 hashCode() 存在问题

创建于 2019-07-19  ·  3评论  ·  资料来源: projectlombok/lombok

使用 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 的情况下,我们遇到了同样的问题。

可能返回对象实例的哈希码而不是硬编码常量

您是否已经采取了这种情况,或者您知道解决这种情况的方法吗?!

版本信息

  • 龙目岛 => 1.18.8
  • 平台 => Windows 10 JDK 11.0.4 IntelliJ

最有用的评论

43 可能与任何其他数字一样好,并且优于 -1、0 和 1。使其可配置会增加维护负担,但附加值非常低。

对 null 使用 Identity 哈希码会破坏 equals 合约。

所有3条评论

因此,当 pk = null 和其他 pk = 43 的实例时,它将返回相同的哈希码

这没关系。 此外,无论您选择什么,总会有哈希冲突。

请注意, Arrays.hashCodeString.hashCode和许多其他的会产生大量的碰撞,而不是不必要的。

可能返回对象实例的哈希码而不是硬编码常量

在我手动编写的代码中,我断言在分配id之前不会调用它。 这肯定很奇怪,但所有替代方案也是如此。

在这种情况下,可以创建一个注释参数,该参数可以告诉当 PK 为空时应该使用哪个值。 默认为 43。

这将为开发人员提供更多控制权。

@EqualsAndHashCode(of = "pk", ifAnyNull = -1)

因此,对于任何为空的字段,它将使用 -1 而不是 43

43 可能与任何其他数字一样好,并且优于 -1、0 和 1。使其可配置会增加维护负担,但附加值非常低。

对 null 使用 Identity 哈希码会破坏 equals 合约。

此页面是否有帮助?
0 / 5 - 0 等级