Java .equals() 子类的实例?为什么不称超类为相等,而不是让它成为最终的呢?

2022-09-03 15:23:48

它在Object的javadoc中陈述:.equals(Object)

它是对称的:对于任何非空引用值 x 和 y,x.equals(y) 应返回 true 当且仅当 y.equals(x) 返回 true。

在示例代码中,几乎在任何地方我都看到被覆盖的方法,它用作首批测试之一,例如在这里:在重写等于和哈希代码时必须考虑哪些问题/陷阱?.equals(Object)instanceof

public class Person {
    private String name;
    private int age;

    public boolean equals(Object obj) {
        if (obj == null)
            return false;
        if (obj == this)
            return true;
        if (!(obj instanceof Person))
            return false;
        ...
    }

}

现在有在 :class SpecialPerson extends Personequals

        if (!(obj instanceof SpecialPerson))
            return false;

我们不保证这是对称的。例如,这里已经讨论过:any-reason-to-prefer-getclass-over-instanceof-when-generating-equals.equals()

Person a = new Person(), b = new SpecialPerson();

a.equals(b);    //sometimes true, since b instanceof Person
b.equals(a);    //always false

也许我应该在SpecialPerson的平等直接调用超级的开头添加?

    public boolean equals(Object obj) {
        if( !obj instanceof SpecialPerson )
            return super.equals(obj);
        ... 
        /* more equality tests here */
    }

答案 1

许多示例使用有两个原因:a)它将空检查和类型检查折叠为一个或b)该示例用于Hibernate或其他一些代码重写框架。instanceof

“正确”(根据JavaDoc)解决方案是使用。这适用于Java,因为类是单例,而VM保证了这一点。如果你是偏执狂,你可以使用,但两者实际上是等价的。this.getClass() == obj.getClass()this.getClass().equals(obj.getClass())

这在大多数情况下都有效。但有时,Java框架需要用字节码做“聪明”的事情。这通常意味着他们会自动创建子类型。由于子类型应被视为与原始类型相等,因此必须以“错误”的方式实现,但这并不重要,因为在运行时,子类型都将遵循某些模式。例如,在调用 setter 之前,他们会做其他事情。这对“平等”没有影响。equals()

正如你所注意到的,当你有这两种情况时,事情开始变得丑陋:你真的扩展了基类型,并且你把它与自动子类型生成混合在一起。如果这样做,则必须确保永远不要使用非叶类型。


答案 2

你在这里错过了一些东西。我将尝试强调这一点:

假设你有,然后我相信你不希望这两个对象相等。因此,它确实按要求工作,相等必须返回false。Person person = new Person()Person personSpecial = new SpecialPerson()

此外,对称性指定两个类中的方法必须同时服从它。如果一个等于返回 true,另一个返回 false,那么我会说缺陷在于等于覆盖。equals()


推荐