简体   繁体   中英

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

Having interface

interface Animal extends Comparable<Animal> {
}

and 2 classes

class Dog implements Animal {

}

and

class Cat implements Animal {

}

What compareTo(Animal o) should return when arguement is not the same concrete implementation of Animal ?

Should it throw IllegalArgumentException ?

As example if I pass Dog instance to Cat.compareTo() . I can not compare them as they are different types. I can not refer to super.compareTo() as their super is Object type which doesn't implement Comparable . Casting Dog to Cat will throw ClassCastException .

interface Animal shouldn't be implementing Comparable<Animal> in the first place if you don't want its subclasses to be mutually comparable.

There is a relevant quote from Effective Java 2nd Ed , in Item 8 "Consider implementing Comparable" (I copied much of the following from my answer to this question ):

One consequence of these three provisions [of the compareTo contract] is that the equality test imposed by a compareTo method must obey the same restrictions imposed by the equals contract: reflexivity, symmetry, and transitivity. Therefore the same caveat applies: there is no way to extend an instantiable class with a new value component while preserving the compareTo contract, unless you are willing to forgo the benefits of object-oriented abstraction (Item 8).

So, what this says is that provided your subclass doesn't have any more values than the superclass used to determine ordering , implementing Comparable<Supertype> is reasonable.

The implication of this, in addition to the general requirements of the Comparable , is that Comparable<Superclass> should be implemented identically in Superclass and all subclasses.

When you define Ainimal as:

interface Animal extends Comparable<Animal> {
}

you're saying that any Animal can be compared to another Animal .

If you only want to compare Dog to Dog , you should define it this way:

interface Animal {
}

class Dog implements Animal, Comparable<Dog> {

    @Override
    public int compareTo(Dog o) {
        ...
    }
}

The comparable interface only states some things how to work together with 'equals', for example, that compateTo() should return 0 if equals returns 0. https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Comparable.html

So actually it depends. If it makes sense to your program, you could cast to Animal :

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

So if you want to sort Animal for size or for the number of search results on Google by using compareTo this would be a valid implementation.

It really depends of whether you want to be able to compare a Cat and a Dog. Broadly speaking, there are different possibilities

  1. Compare all Animal instances with an order consistent with Equal

    You could for example use different attributes of animals in a way that 2 different animals cannot have all attributes the same. If it makes sense you can use the class name as such an attribute to compare a Cat and a Dog having all other attributes identical

  2. Compare all Animal instances with an order non consistent with Equal

    Just a slight variation of the above: two animal will compare equal if their attributes are identical, even if equals between them will return false. Beware, it may be dangerous (even if possible), according to the Javadoc for Comparable

    It is strongly recommended (though not required) that natural orderings be consistent with equals. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of the equals method.

  3. Only compare Animal instances in one class (and of course its subclasses). In that case, the declaration of the interface should be changed to use generics:

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

    and 2 classes

     class Dog implements Animal<Dog> { } 

    and

     class Cat implements Animal<Cat> { } 

它应该引发不匹配错误,如果可能的话,在比较之前使用instanceOf运算符匹配相关对象。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM