如果参数是同一接口的不同实现,应该返回什么 compareTo() ?



具有接口

interface Animal extends Comparable<Animal> {
}

和2个班级

class Dog implements Animal {
}

class Cat implements Animal {
}

当参数不是Animal的具体实现时,compareTo(Animal o)应该返回什么?

它应该扔IllegalArgumentException吗?

例如,如果我Dog实例传递给Cat.compareTo().我无法比较它们,因为它们是不同的类型。我不能参考super.compareTo()因为他们的超级是Object类型,它没有实现Comparable。将Dog投到Cat会抛出ClassCastException.

如果你不希望它的子类相互比较,interface Animal首先不应该实现Comparable<Animal>

在第 8 项"考虑实现可比性"中,有一段来自Effective Java 2nd Ed的相关引述(我从我对这个问题的回答中复制了以下内容(:

[compareTo合同]这三项条款的一个后果是,平等标准 比较方法必须遵守 equals 协定施加的相同限制: 反身性、对称性和传递性。因此,同样的警告适用: 没有办法用新的值组件扩展可实例化的类,而 保留比较合同,除非您愿意放弃 面向对象的抽象(项目8(。

所以,这说明的是,如果你的子类没有比用于确定排序的超类更多的值,实现Comparable<Supertype>是合理的。

除了Comparable的一般要求之外,这意味着Comparable<Superclass>应该在Superclass和所有子类中以相同的方式实现。

当您将Ainimal定义为:

interface Animal extends Comparable<Animal> {
}

你是说任何Animal都可以与另一个Animal进行比较.

如果只想将DogDog进行比较,则应按以下方式定义:

interface Animal {
}
class Dog implements Animal, Comparable<Dog> {
@Override
public int compareTo(Dog o) {
...
}
}

comparable接口仅说明如何与"equals"一起使用的一些内容,例如,如果compateTo()返回 0,则equals应返回 0。 https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Comparable.html

所以实际上这取决于。 如果它对你的程序有意义,你可以投射到Animal

int compareTo(Dog o)
{
Animal other = (Animal) o;
...
}

因此,如果您想使用 Animal 的大小或 Google 上的搜索结果数量对 Animal 进行排序compareTo这将是一个有效的实现。

这实际上取决于您是否希望能够比较猫和狗。从广义上讲,有不同的可能性

  1. 与相等一致的顺序比较所有动物实例

    例如,您可以使用动物的不同属性,即 2 种不同的动物不能具有相同的所有属性。如果有意义,您可以使用类名作为这样的属性来比较具有所有其他属性相同的猫和狗

  2. 比较顺序与相等不一致的所有动物实例

    只是上述的轻微变化:如果两只动物的属性相同,它们将比较相等,即使它们之间的equals也会返回 false。当心,根据Javadoc for Comparable

    强烈建议(尽管不是必需的(自然排序与等于一致。之所以如此,是因为没有显式比较器的排序集合(和排序映射(在与自然顺序与等式不一致的元素(或键(一起使用时行为"奇怪"。特别是,这样的排序集合(或排序映射(违反了集合(或映射(的一般契约,该约定是根据 equals 方法定义的。

  3. 只比较一个类(当然还有它的子类(中的动物实例。在这种情况下,接口的声明应更改为使用泛型:

    interface Animal<T> extends Comparable<T> {
    }
    

    和2个班级

    class Dog implements Animal<Dog> {
    }
    

    class Cat implements Animal<Cat> {
    }
    

最新更新