Java - 基类和子类中的方法相等

2022-09-01 20:12:29

我有一个简单的基类,后来由许多单独的类扩展,这些类可能会引入新字段,但不一定。我在基类中定义了一个 equals 方法,但也为几个子类重写了该方法。是否可以在基类/子类中混合使用定义?在我的情况下,这是为了避免代码重复检查相同的字段。


答案 1

看看Angelika Langer的“Implementing equals() To Allow Mixed-Type Comparison”。

以下是一些问题的简要说明和可能的解决方案:

平等合同说(其中包括):

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

这意味着,如果您的子类正在引入新字段,并且您正在将基类的对象(或另一个不覆盖 equals 的子类)与此子类的对象进行比较,则可能会遇到问题。

请勿执行以下操作:

class BaseClass {
    private int field1 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BaseClass) {
            return field1 == ((BaseClass) obj).field1;
        }
        return false;
    }
}

class BadSubClass extends BaseClass {
    private int field2 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof BadSubClass) {
            return super.equals(obj) 
                    && field2 == ((BadSubClass) obj).field2;
        }
        return false;
    }
}

因为您得到

BaseClass baseClass = new BaseClass();
BadSubClass subClass = new BadSubClass();

System.out.println(baseClass.equals(subClass)); // prints 'true'
System.out.println(subClass.equals(baseClass)); // prints 'false'

一个可能的解决方案:

将 -check 替换为类比较:instanceof

obj != null && obj.getClass() == getClass()

使用此解决方案,的对象永远不会等于任何子类的对象。BaseClass

如果创建另一个没有该方法的对象,则两个 -对象可以开箱即用地彼此相等(如果检查决定如此),但 -object 永远不会等于 -object。SubClass@OverrideequalsSubClassBaseClass.equalsSubClassBaseClass

一个好的实现可以如下所示:

class BaseClass {
    private int field1 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj != null && obj.getClass() == getClass()) {
            return field1 == ((BaseClass) obj).field1;
        }
        return false;
    }
}

class GoodSubClass extends BaseClass {
    private int field2 = 0;

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof GoodSubClass) {
            return super.equals(obj) && field2 == ((GoodSubClass) obj).field2;
        }
        return false;
    }
}

有关更高级的问题及其解决方案,请参阅上面提到的文章。


答案 2

不可以,在引入与 equals 方法相关的新字段时,不可能遵守 equals 协定。有关更多信息,请参阅Joshua Bloch的“Effective Java”。

编辑:

我现在手头没有这本书,但我认为如果基类是抽象的/无法实例化是可以的。


推荐