Java - 基类和子类中的equals方法

Bob*_*r02 18 java equals

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

小智 33

看看Angelika Langer的"实现等于()允许混合型比较".

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

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

对称性:对于任何非空的参考值x和y,x.equals(y)的应返回true,当且仅当y.equals(x)返回真.

这意味着如果您的子类引入了新字段并且您正在将基类的对象(或不重写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;
    }
}
Run Code Online (Sandbox Code Playgroud)

因为你得到了

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

System.out.println(baseClass.equals(subClass)); // prints 'true'
System.out.println(subClass.equals(baseClass)); // prints 'false'
Run Code Online (Sandbox Code Playgroud)

可能的解决方案:

instanceof类比较替换-check:

obj != null && obj.getClass() == getClass()
Run Code Online (Sandbox Code Playgroud)

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

如果你创建另一个SubClass没有@Override了的equals方法中,两个SubClass-objects可以彼此相等(如果BaseClass.equals检查决定的话)开箱即用,但SubClass-object永远不会等于BaseClass-object.

一个好的实施可能如下:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • o.getClass() != this.getClass() 有什么问题? (2认同)

Puc*_*uce 6

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

编辑:

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