2

编辑

我做得很糟糕,并且为任何人提供了不完整的信息来确定我的问题的原因。真正的问题是我在 Animal 中有一个嵌套类,它有自己的 .equals ,它在其外部类型上调用 .equals 。(因此,从嵌套类的 .equals 中调用 .equals on animal 调用 .equals on animal)。


我在继承树中有三个类。假设它们是Animal--> Dog<Owner>--> DogWithHumanOwner

所以 DogWithHumanOwner 是通用 Dog 的一个实现,它的所有者专门有一个 Human。

我已经覆盖了 Animal 和 Dog 的 .equal 方法。Dog 的 .equal 方法如下所示:

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (!super.equals(obj))
        return false;

    [other stuff]

    return true;
}

我实际使用的是 DogWithHumanOwner。似乎当我尝试比较两个 DogWithHumanOwner 的相等性时,dogWithHumanOwner 继承了 equals 方法Dog<Owner>,该方法调用 super.equals,这是 dogWithHumanOwner 的超类的 .equals 方法,这是它所在的方法,因此它会导致递归循环和stackoverflow。

(我不需要比较Dog<Owner>类实现的任何特定属性,因为我这样做Dog<Owner>并且所有者需要有适当的 equals 方法。)

编写避免此问题的 .equals 方法的最佳实践是什么?我在画一个空白。我应该只手动测试相等性而不调用 super 吗?

编辑:我不得不删除 BlackLabs,因为我为什么要使用 blackLabs 这样做是没有意义的。

4

2 回答 2

4

编辑后编辑:

简而言之,是的,根本不打电话super.equals。此外,请确保super.equals使用类相等性检查其传入对象的类,而不是instanceof. 这就是Object.equals默认情况下所做的,所以如果Animal没有声明 an equals,你很好。

不过,我的其余答案仍然是相关的,因为上面基本上是对上一段中结论的总结,就像以前一样。基本上,如果超类不需要等于子类的实例,那么每个人都可以检查对象是否相等(不是instanceof)以及他们想要的任何状态。如果超类只检查instanceof(不是更严格的相等性),那么基本上子类不能检查除了超类检查的任何额外状态。

在您的情况下, Animal 不会检查任何内容,而 Dog 会。所以你可以走了。

原答案如下:


如果(a)它们在某些特定的 BlackLab 品质上相等并且(b)它们在 Dogness 上相等,您是否认为两个 BlackLab 是相等的?如果是这样,这是一个坏主意!它破坏了Object.equals指定的相等的传递属性。想象一下你有:

  • 黑实验室
  • BlackLab b
  • 狗c

假设这三个人的“dogness”是相等的,比如他们的体重、身高和名字。但是 BlackLabness 的两个 BlackLab 并不相同,比如他们的外套的光泽。现在你有:

  • a = c
  • b = c
  • a != b // 破坏传递性!

另一方面,BlackLab.equals如果不添加任何额外的检查 - 那么您根本不需要覆盖它。它只会继承 Dog 的相等性,这就是你想要的。

正如 Mattias Buelens 指出的那样,您可以通过更严格的类型检查来解决这个问题——要求两个对象属于同一个确切的类,而不是使用instanceof. 这修正了平等合同,但代价是体重 80 磅的 BlackLab“雷克斯”不等于体重 80 磅、名为“雷克斯”的未指定品种的狗。如果您考虑您需要的特定用例,您可能会发现这是完全可以接受的。

于 2013-05-03T20:24:11.607 回答
2

你误会了supersuper.x()始终是对调用它的类的超类的调用

super.equals()在您的情况下调用的类是Dog而不是BlackLab所以它调用Dog(因此Animal.equals())的超类而不是BlackLab(将是Dog)的超类。

可以这样想:如果你不覆盖 a equals(或任何其他方法),它隐含地定义为:

class BlackLab extends Dog {
  ...
  boolean equals( Object o ) {
    return super.equals( o );
  }
  ...
}
于 2013-05-03T20:33:14.587 回答