比较扩展相同超类的类

时间:2016-03-18 14:42:18

标签: java polymorphism equals

考虑我们有一个类MyEntity,它有一些带有getter和setter的字段。此外,课程EntityAEntityB会延伸MyEntityMyEntityA中的某些字段不在MyEntityB中,反之亦然。在我们讨论实体时,EntityAEntityB确实有自己的equals - 方法看起来像

@Override
public boolean equals(Object other) {
    if ((this == other))
        return true;
    if ((other == null))
        return false;
    if (!(other instanceof EntityA))
        return false;
    EntityA castOther = (EntityA) other;

    return ((this.getId() == castOther.getId()) || (this.getId() != null && castOther.getId() != null && this.getId().equals(castOther.getId())));
}

equals - 方法用于hibernate以识别唯一实体。

现在我想将EntityA的实例与EntityB的实例进行比较。如果MyEntity中的所有字段都匹配,我将它们定义为相同。

为了检查这个,我让eclipse为我生成equals方法并将其复制到类似isEqualWithRegardsToContent(MyEntity other)的方法。

我发现这种方法存在一个大问题: 如果某人曾向其中一个实体添加新列并且未更新isEqualWithRegardsToContent(MyEntity other) - 方法,则会出现错误:实体可能被视为内容相同,尽管它们不是。< / p>

我没有看到单元测试会对此有所帮助。

你有什么最佳做法吗?

4 个答案:

答案 0 :(得分:2)

一般来说,在处理继承树时,不可能拥有完全正常的功能。 superclass.equals(subclass)不会返回与subclass.equals(superclass)相同的结果,打破对称性(这是相等的基本合同 - 如果a.eq(b),那么b.eq(a))。

您只能在顶层实现equals(),从而从超类的角度比较整个层次结构。这将有效,但不会被&#34;所有字段&#34; (只有超类中的那些)。通常可以通过主键来比较实体

就我个人而言,我通常不会将2 - equals()hashcode() i保留用于非多态的简单数据存储类(或用于在地图中查找的键)。

在此处查看详细信息 - http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals-2.html

答案 1 :(得分:1)

比如说,你在超类中有equals()方法来比较常见属性。

在子类equals()中,您可以先调用super.equals(),然后,如果比较对象也是此类,则仅比较特定属性。所以你在EntityA写道:

@Override
public boolean equals(Object o) {
    boolean eq = super.equals(o);
    if (eq && o instanceof EntityA) {
        EntityA e = (EntityA) o;
        return Objects.equals(this.propOne, e.propOne) 
            && Objects.equals(this.propTwo, e.propTwo)
            && // compare other properties
    } else 
       return eq;
}

这样,同一具体类的对象将通过完整的属性集进行比较,包括公共属性和特定属性,不同类的实例将仅通过公共属性进行比较。虽然这是违反合同传递属性的非标准方式,但它可以解决您的特定问题。

答案 2 :(得分:0)

课程&#39; equals()方法应该只适用于该类的其他实例。如果您想将EntityAEntityBequals()进行比较,则应在equals()(以及MyEntity)上定义hashCode()方法,并且EntityAEntityB都不应该有equals()个方法。否则,你很可能会与contract for equals()发生冲突。像Hibernate这样的库依赖equals()正确地遵守合同。

答案 3 :(得分:0)

如果我正确理解您的问题:

  • 您有一个名为MyEntity的课程,缺少getId字段
  • 您有2个子类EntityAEntityB,它们都定义了id字段但形成了不同的生成器
  • 在比较类EntityA(resp。EntityB)的2个对象时,他们比较相等,当且仅当他们的id字段具有相同的值时 - 我假设在那种情况下所有字段都继承自{{1具有相同的值
  • MyEntity对象与EntityA对象进行比较时,如果且仅当从EntityB继承的所有字段相等时,它们应该相等。

以下是您可以做的事情:

  • MyEntity中声明equals方法,当且仅当所有字段都相等时才返回true - 如果您不能使用MyEntity方法,请将方法命名为{{1} (例如)
  • 在子类equals中声明相等的方法(分别为ABequals

    EntityA

在这种情况下,必须在使用所有字段的EntityB类中实现哈希方法,并且不应在子类中覆盖它。这样,您可以确保两个比较相等的对象具有相同的哈希值 - 上面的定义已经保证@Override public boolean equals(Object other) { if ((this == other)) return true; if ((other == null)) return false; if (!(other instanceof EntityA)) return MyEntity.equals(other); // or return ABequals(other); EntityA castOther = (EntityA) other; return ((this.getId() == castOther.getId()) || (this.getId() != null && castOther.getId() != null && this.getId().equals(castOther.getId()))); } 函数是等价关系。