是的——这就是多态性背后的全部原则,特别是Liskov 替换原则。基本上,如果 A 是 B 的子类,那么您应该能够在任何可以使用 B 的地方使用 A,并且它的行为本质上应该与 B 的任何其他实例(或 B 的其他子类)相同。
所以,它不仅会发生,而且几乎总是你想要发生的事情。在子类中通常是错误compareTo
的。
为什么?好吧,Comparable<T>
合同的一部分是比较是传递的。由于你的超类可能不知道它的子类在做什么,如果一个子类compareTo
以这样一种方式覆盖,它给出的答案与它的超类不同,它就会违反合同。
例如,假设您有类似 Square 和 ColorSquare 的东西。SquarecompareTo
比较两个正方形的大小:
@Override
public int compareTo(Square other) {
return this.len - other.len;
}
...而 ColorSquare 还添加了颜色比较(假设颜色是 Comparable)。Java 不会让你有 ColorSquare 实现Comparable<ColorSquare>
(因为它的超类已经实现Comparable<Square>
),但你可以使用反射来解决这个问题:
@Override
public int compareTo(Square other) {
int cmp = super.compareTo(other);
// don't do this!
if (cmp == 0 && (other instanceof ColorSquare)) {
ColorSquare otherColor = (ColorSquare) other;
cmp = color.compareTo(otherColor.color);
}
return cmp;
}
乍一看,这看起来很无辜。如果两个形状都是 ColorSquare,它们会比较长度和颜色;否则,他们只会比较长度。
但是如果你有:
Square a = ...
ColorSquare b = ...
ColorSquare c = ...
assert a.compareTo(b) == 0; // assume this and the other asserts succeed
assert a.compareTo(c) == 0;
// transitivity implies that b.compareTo(c) is also 0, but maybe
// they have the same lengths but different color!
assert b.compareTo(c) == 1; // contract is broken!