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

What should compareTo() return if argument is different implementation of the same interface?

提问人:blekione 提问时间:5/18/2018 更新时间:5/18/2018 访问量:192

问:

有接口

interface Animal extends Comparable<Animal> {
}

和 2 节课

class Dog implements Animal {

}

class Cat implements Animal {

}

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

它应该扔吗?IllegalArgumentException

例如,如果我将实例传递给 .我无法比较它们,因为它们是不同的类型。我不能把他们的超级类型称为不实现的类型。投射到将抛.DogCat.compareTo()super.compareTo()ObjectComparableDogCatClassCastException

Java 接口 可比

评论

2赞 Kayaman 5/18/2018
如果你不能比较猫和狗,那么接口定义是错误的(因为它声称你可以将任何动物与其他动物进行比较)。
2赞 khelwood 5/18/2018
如果你打算(例如)把一堆不同的动物放在一个列表中并对它们进行排序,那么所有动物都应该相互比较。如果您不打算支持比较两种不同类型的动物,那么不应该; 应该是并且应该是 .AnimalAnimalComparable<Animal>CatComparable<Cat>DogComparable<Dog>

答:

5赞 Andy Turner 5/18/2018 #1

interface Animal如果您不希望其子类相互比较,则首先不应实现。Comparable<Animal>

在《Effective Java 2nd Ed》第 8 项“考虑实现 Comparable”中引用了一段相关的引文(我从对这个问题的回答中复制了以下大部分内容):

[合同]这三项规定的一个后果是,由以下人员执行的平等测试 compareTo 方法必须遵守 equals 协定施加的相同限制: 反身性、对称性和传递性。因此,同样的警告也适用: 没有办法使用新的值组件扩展可实例化的类,而 保留 compareTo 合约,除非您愿意放弃 面向对象的抽象(第 8 项)。compareTo

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

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

2赞 xingbin 5/18/2018 #2

当您定义为:Ainimal

interface Animal extends Comparable<Animal> {
}

你是说任何一个都可以与另一个相提并论.AnimalAnimal

如果你只想比较 ,你应该这样定义它:DogDog

interface Animal {
}

class Dog implements Animal, Comparable<Dog> {

    @Override
    public int compareTo(Dog o) {
        ...
    }
}
0赞 maze 5/18/2018 #3

该接口只说明了一些如何与“equals”一起工作的东西,例如,如果返回 0,则返回 0。https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Comparable.htmlcomparablecompateTo()equals

所以实际上这要看情况。 如果它对你的程序有意义,你可以强制转换为:Animal

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

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

0赞 Serge Ballesta 5/18/2018 #4

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

  1. 比较所有 Animal 实例,其顺序与 Equal 一致

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

  2. 比较所有 Animal 实例,其顺序与 Equal 不一致

    只是上面的一个小变化:如果两种动物的属性相同,它们将相等,即使它们之间会返回 false。请注意,根据 Javadoc for Comparable 的说法,它可能是危险的(即使可能)equals

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

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

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

    和 2 节课

    class Dog implements Animal<Dog> {
    
    }
    

    class Cat implements Animal<Cat> {
    
    }