Classes implementing Comparable<T>
typically implement it for themselves, e.g.
class MyInteger implements Comparable<MyInteger> { ... }
class MyString implements Comparable<MyString> { ... }
But there's nothing to stop you implementing it for a different type:
class MyString implements Comparable<MyInteger> { ... }
which would allow you to compare a MyString
to a MyInteger
.
As is described in the Javadoc, Comparable
is intended to model the natural ordering, which is a total order, and so to be able to have anti-symmetry, the type of the argument of compareTo
should be the same as the type on which that method is defined.
But are there any practical uses (abuses) of implementing class SomeType implements Comparable<OtherType>
?
Update: The answers that Joni and I have provided give practical examples of where Comparable<Supertype>
are implemented implicitly, i.e. where your classes implement that interface transitively. It would be interesting to know if anybody has an example where it might be used explicitly.
The Comparable interface is used to compare an object of the same class with an instance of that class, it provides ordering of data for objects of the user-defined class.
The benefit of implementing the interface is that some methods specifically require object that implements the Comparable interface. It gives them a guarantee that the object you're passing has a compareTo method with the correct signature.
The Comparable interface defines the compareTo method used to compare objects. If a class implements the Comparable interface, objects created from that class can be sorted using Java's sorting algorithms.
When you implement Comparable interface, you need to implement method compareTo() . You need it to compare objects, in order to use, for example, sorting method of ArrayList class.
If there is a parent/child relationship you do find this. For example, the Enum class implements Comparable<E>
with E being a type parameter. All enums share this one compareTo implementation.
To clarify: Enum<ConcreteClass>
implements Comparable<ConcreteClass>
. If it followed the pattern you'd expect it to implement Comparable<Enum<ConcreteClass>>
The obvious (in hindsight) case where you encounter this is in subclasses of classes implementing Comparable
:
abstract class Superclass implements Comparable<Superclass> {}
abstract class Subclass extends Superclass {}
System.out.println(Subclass.class.getGenericInterfaces()[0]);
// Prints Comparable<Superclass>
As ever, there is a great insight in Bloch's Effective Java 2nd Ed, in Item 8 "Consider implementing Comparable":
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.
That suggests that compareTo
should be marked final
, if Superclass
is a class. If it's an interface, you could provide a default implementation in Java 8+; but there's no (in-built) way to enforce that the method is not overridden differently in implementing classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With