约书亚·布洛赫在他的书“有效
Java”中写道,当派生类向检查添加附加字段时,关于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); } }
当我使用相同的颜色字符串创建每个类的一个实例时,equals()的对称性将被破坏:
Bicycle bicycle = new Bicycle("blue"); Car car = new Car("blue","Mercedes"); bicycle.equals(car) <- true car.equals(bicycle) <- false
我不确定如何处理这个最好的方法.在抽象类中声明equals()作为抽象,以强制执行子类?但是,在抽象类中根本没有声明equals()可以实现相同的效果.
解决方法
Java的等同契约在这样的情况下特别多,最终这一切都成为程序员的偏好和需求的问题.我记得遇到这个同样的问题,我遇到了
this article,考虑到与Java的平等合同时,它出现了几个可能性和问题.它基本上最终说,没有办法适当地做到这一点,而不违反Java等于合同.
在处理抽象类时,我个人的喜好是不要给抽象类一个equals方法.没有意义你不能有两个抽象类型的对象;你应该怎么比较呢?相反,我给每个子类自己的equals,并且运行时处理其余的每当equals()被调用.总的来说,我最经常遵循的文章中提出的解决方案是“只有完全相同的类的对象可能被比较”,这似乎对我来说最为明智.