从抽象类派生时如何服从equals()的契约

Ste*_*ler 10 java oop inheritance

在他的" 有效Java"一书中,Joshua Bloch写了关于equals()派生类在检查中添加其他字段的合同中发生的陷阱.通常情况下,这会破坏对称性,但Bloch声明"您可以在不违反equals合同的情况下将值组件添加到抽象类的子类".

显然这是真的,因为没有抽象类的实例,所以没有违反的对称性.但是其他子类呢?我写了这个例子,故意省略哈希码实现和空检查以保持代码简短:

public abstract class Vehicle {

    private final String color;

    public Vehicle(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;

        if (!(o instanceof Vehicle)) return false;

        Vehicle that = (Vehicle) o;

        return color.equals(that.color);
    }

}

public class Bicycle extends Vehicle {

    public Bicycle(String color) {
        super(color);
    }

}

public class Car extends Vehicle {

    private final String model;

    public Car(String color, String model) {
        super(color);
        this.model = model;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;

        if (!(o instanceof Car)) return false;

        Car that = (Car) o;

        return getColor().equals(that.getColor()) && model.equals(that.model);
    }

}
Run Code Online (Sandbox Code Playgroud)

当我使用相同的颜色字符串创建每个类的一个实例时,对称性equals()被破坏:

Bicycle bicycle = new Bicycle("blue");
Car car = new Car("blue", "Mercedes");

bicycle.equals(car) <- true
car.equals(bicycle) <- false
Run Code Online (Sandbox Code Playgroud)

我不确定如何处理这个最好的方法.equals()在抽象类中声明为抽象,以在子类中强制实现?但是,通过equals ()在抽象类中完全不进行声明,可以实现同样的效果.

Mut*_*pus 7

在这种情况下,Java 的 equals 契约变得特别参差不齐,最终这一切都取决于程序员的偏好和需求。我记得遇到过同样的问题,我遇到了这篇文章,它在考虑与 Java 的 equals 合同时讨论了几种可能性和问题。它基本上最终说没有办法在不破坏 Java 等价契约的情况下正确地做到这一点。

在处理抽象类时,我个人的偏好是根本不给抽象类一个 equals 方法。这没有意义。你不能有两个抽象类型的对象;你应该如何比较它们?相反,我为每个子类提供了自己的 equals,并且运行时equals()在调用时处理其余的。总的来说,我最常遵循的文章中提出的解决方案是“只能比较完全相同类别的对象”,这对我来说似乎是最明智的。