Java 从调用到super.equals的递归.equals方法

Java 从调用到super.equals的递归.equals方法,java,equals,Java,Equals,编辑 我的工作做得很差,为任何人提供了不完整的信息来确定问题的原因。真正的问题是,我在Animal中有一个嵌套类,它有自己的.equals,在其外部类型上调用.equals。(因此调用.equals on animal调用了嵌套类的.equals中的.equals on animal) 我在继承树中有三个类。让我们假设它们是动物-->狗-->狗和人类主人 所以DogWithHumanOwner是通用狗的一个实现,它的主人专门有一个人 我已经超越了动物和狗的。平等的方法。Dog的.equal方法

编辑

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


我在继承树中有三个类。让我们假设它们是
动物
-->
-->
狗和人类主人

所以DogWithHumanOwner是通用狗的一个实现,它的主人专门有一个人

我已经超越了动物和狗的。平等的方法。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是来自
Dog
的equals方法,它调用super.equals,这是DogWithHumanOwner的超类.equals方法,这是它所在的方法,因此它会导致递归循环和堆栈溢出

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

编写.equals方法以避免此问题的最佳实践是什么?我画的是空白。我是否应该在根本不调用super的情况下手动测试等式


编辑:我必须删除BlackLabs,因为我不明白为什么要对BlackLabs执行此操作。

编辑后编辑:

简而言之,是的,就是根本不要调用
super.equals
。另外,确保
super.equals
使用类相等性检查其传入对象的类,而不是
instanceof
。默认情况下,
Object.equals
就是这么做的,所以如果
Animal
没有声明
equals
,你就可以了

不过,我的回答的其余部分仍然相关,因为上述内容与以前一样,基本上是最后一段结论的总结。基本上,如果超类不需要与子类的实例相等,那么每个人都可以检查对象相等性(而不是
instanceof
)和他们想要的任何状态。如果超类只检查
instanceof
(不是更严格的等式),那么子类基本上不能检查超类检查之外的任何额外状态

在你的例子中,动物不检查任何东西,而狗检查任何东西。所以你可以走了

原始答复如下:


你是否认为两个黑实验室是相等的,如果(a)它们在某些特定的黑实验室性质上是相等的,(b)它们在狗性上是相等的?如果是这样,这是个坏主意!它打破了由指定的等式的传递属性。想象一下你有:

  • 黑实验室a
  • 黑实验室b
  • 狗c
假设这三个人的“狗性”是相等的,比如他们的体重、身高和名字。但这两个黑实验室的黑度并不相等,比如它们外套的光泽。现在你有:

  • a=c
  • b=c
  • a!=打破及物性
如果另一方面,
BlackLab.equals
没有添加任何额外的检查,那么您根本不需要覆盖它。它只是从狗那里继承了平等,这就是你想要的


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

您误解了
super
super.x()

在你的例子中,调用
super.equals()
的类是
Dog
而不是
BlackLab
,因此它调用
Dog
(因此
Animal.equals()
)的超类,而不是
BlackLab
(即
Dog
)的超类

可以这样想:如果不重写
equals
(或任何其他方法),则隐式定义为:

class BlackLab extends Dog {
  ...
  boolean equals( Object o ) {
    return super.equals( o );
  }
  ...
}

Dog
的超类应该是
Animal
。调用其
equals
函数不应导致递归。@Madbreaks-注意
BlackLab.equals
未被重写,因此它默认为
Dog.equals
,它是
super.equals
,因此是
Dog.equals
,因为
BlackLab.super
在调用
super.equals
中的
Dog
将始终解析为
Animal.equals
(它不会根据运行时类型而改变)。呃,任何人都知道@coray的转义字符是什么,可以将内联代码格式与`character一起使用,例如`Dog`格式转换为
Dog
。您还可以使用and for<和>。请注意,您可以通过添加
this.getClass()==obj.getClass()
check.Hmmm来保持及物性。也许我的例子有点糟糕。让我试着把它修好。。。我修正了它来解释这其中的原因是因为Dog类中有一个泛型,实际上我在Animal中有一些相关的东西。我删除了对super.equals的调用,并使用getter添加了这些检查。所以我现在可以用了,虽然我真的不太喜欢它。如果我改变Animal及其equals方法的行为,我就不需要修改其Decentant类中的相同内容,这就是继承的意义!他们已经使用了类相等,而不是instanceof。(虽然我最近也学到了