关于java:实现等于合同的正确方法

Right way to implement equals contract

本问题已经有最佳答案,请猛点这里访问。

我有一个叫做用户的域对象。用户的属性包括ssoid、name、email、createdby、createddate和userrole。其中,SSOID必须是唯一的,因为没有两个用户可以拥有相同的SSO ID。因此,我的equals方法检查SSO ID,并返回true或false。

1
2
3
4
5
@Override public boolean equals(Object o) {
    if (!(o instanceof User))
      return false;
    return user.getSsoId().equals((User)o.getSsoId());
}

我认为这是一个不正确的实现,尽管就业务规则而言它是正确的。对于具有相同SSO ID但具有不同名称或电子邮件或两者的值的两个对象,上述实现将返回true。我应该改变我的平等合同来检查所有领域的平等吗?你有什么建议?


这对"技术平等"几乎是正确的,但对"自然平等"则不是正确的。为了实现最高的技术平等,您还应该测试反射o == this。可能发生的情况是,对象还没有持久化到数据库中,因此还没有技术ID。例如。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class User {

    private Long id;

    @Override
    public boolean equals(Object object) {
        return (object instanceof User) && (id != null)
             ? id.equals(((User) object).id)
             : (object == this);
    }

    @Override
    public int hashCode() {
        return (id != null)
             ? (User.class.hashCode() + id.hashCode())
             : super.hashCode();
    }

}

对于"自然平等",你应该比较所有非技术性质。对于"现实世界的实体",这毕竟比技术平等更强大(但也更昂贵)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class User {

    private String name;
    private Date birth;
    private int housenumber;
    private long phonenumber;

    @Override
    public boolean equals(Object object) {
        // Basic checks.
        if (object == this) return true;
        if (!(object instanceof User)) return false;

        // Property checks.
        User other = (User) object;
        return Objects.equals(name, other.name)
            && Objects.equals(birth, other.birth)
            && (housenumber == other.housenumber)
            && (phonenumber == other.phonenumber);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, birth, housenumber, phonenumber);
    }

}

是的,当有很多属性时,这就是很多代码。有点像样的IDE(Eclipse、NetBeans等)可以为您自动生成equals()hashCode()(以及toString()、getter和setter)。从中获益。在Eclipse中,右键单击代码并查看源(alt+shift+s)菜单选项。

另请参见:

  • jboss:equals和hashcode(考虑到持久性)
  • 休眠:持久类-实现equals()和hashcode()。
  • 相关问题:在Java中重写等值和哈希代码

这是一个棘手的决定。

这是我几个月前考虑散列时遇到的问题。我建议你读一读哈希是什么,因为它与你的答案高度相关…我建议您希望实现某种散列并测试其相等性。

有各种各样的平等…有对象的同一性的平等,对象的数据的平等,整个对象的平等…您还可以在其中包括审计信息。

事实上,"平等"有许多可能的含义。

我通过在所有领域实现一个严格的平等来解决这个问题,仅仅是因为在询问之后,它似乎是平等的直观含义。然后,我为我需要的其他类型的等式构造了方法,并定义了一个包装这些等式的接口。

我不会在object==上测试相等性,因为通常您使用相同的数据测试两个不同的对象,在我的书中,尽管它们引用了不同的内存地址,但数据是相等的。


你所做的似乎很好,而且你没有违反任何equals必须遵守的规则。

您可能仍然希望检查其他字段,而不是更改equals的语义,而是检测业务逻辑中的不一致性,并可能触发断言/异常。


如果在您的模型中,ssoid必须是唯一的,这意味着对于用户的两个实例,其他字段的值不应该不同。如果您想验证这个假设,那么可以使用equals方法中的断言进行验证,前提是开销不是问题。