When should a class be Comparable and/or Comparator?

I have seen classes which implement both Comparable and Comparator. What does this mean? Why would I use one over the other?


The text below comes from Comparator vs Comparable

Comparable

A comparable object is capable of comparing itself with another object. The class itself must implements the java.lang.Comparable interface in order to be able to compare its instances.

Comparator

A comparator object is capable of comparing two different objects. The class is not comparing its instances, but some other class’s instances. This comparator class must implement the java.util.Comparator interface.


Implementing Comparable means "I can compare myself with another object." This is typically useful when there's a single natural default comparison.

Implementing Comparator means "I can compare two other objects." This is typically useful when there are multiple ways of comparing two instances of a type - e.g. you could compare people by age, name etc.


Comparable lets a class implement its own comparison:

  • it's in the same class (it is often an advantage)
  • there can be only one implementation (so you can't use that if you want two different cases)

By comparison, Comparator is an external comparison:

  • it is typically in a unique instance (either in the same class or in another place)
  • you name each implementation with the way you want to sort things
  • you can provide comparators for classes that you do not control
  • the implementation is usable even if the first object is null

In both implementations, you can still choose to what you want to be compared. With generics, you can declare so, and have it checked at compile-time. This improves safety, but it is also a challenge to determine the appropriate value.

As a guideline, I generally use the most general class or interface to which that object could be compared, in all use cases I envision... Not very precise a definition though ! :-(

  • Comparable<Object> lets you use it in all codes at compile-time (which is good if needed, or bad if not and you loose the compile-time error) ; your implementation has to cope with objects, and cast as needed but in a robust way.
  • Comparable<Itself> is very strict on the contrary.

Funny, when you subclass Itself to Subclass, Subclass must also be Comparable and be robust about it (or it would break Liskov Principle, and give you runtime errors).