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