32

I want to know why the .compareTo() is in the Comparable interface while a method like .equals is in the Object class. To me, it seems arbitrary why a method like .compareTo() is not in the Object class already.

To use .compareTo(), you implement the Comparable interface and implement the .compareTo() method for your purposes. For the .equals() method, you simply override the method in your class, since all classes inherit from the Object class.

My question is why is a method like .compareTo() in an interface that you implement rather than in a class like Object? Likewise, why is the .equals() method in the class Object and not in some interface to be implemented?

Captain Man
  • 586
  • 5
  • 16
Wesley
  • 439
  • 1
  • 4
  • 7
  • 4
    possible duplicate of [Java: why is there a Comparator interface but no Hasher and Equator?](http://programmers.stackexchange.com/questions/283194/java-why-is-there-a-comparator-interface-but-no-hasher-and-equator) – Andres F. May 07 '15 at 14:13
  • 2
    It's a design choice of the Java language (doesn't necessarily mean it was the right choice). In other languages, e.g. [Haskell](https://www.haskell.org/), you have to _implement the equality interface_ to get value equality (actually you provide an instance to the `Eq` typeclass). – mucaho May 07 '15 at 20:31
  • 2
    Related meta question: **[Are these questions duplicates of each other?](http://meta.programmers.stackexchange.com/q/7412/22815)** –  Jun 04 '15 at 18:42

4 Answers4

59

Not all objects can be compared, but all objects can be checked for equality. If nothing else, one can see if two objects exist at the same location in memory (reference equality).

What does it mean to compareTo() on two Thread objects? How is one thread "greater than" another? How do you compare two ArrayList<T>s?

The Object contract applies to all Java classes. If even one class cannot be compared to other instances of its own class, then Object cannot require it to be part of the interface.

Joshua Bloch uses the key words "natural ordering" when explaining why a class might want to implement Comparable. Not every class has a natural ordering as I mentioned in my examples above, so not every class should implement Comparable nor should Object have the compareTo method.

...the compareTo method is not declared in Object. ... It is similar in character to Object's equals method, except that it permits order comparisons in addition to simple equality comparisons, and it is generic. By implementing Comparable, a class indicates that its instances have a natural ordering.

Effective Java, Second Edition: Joshua Bloch. Item 12, Page 62. Ellipses remove references to other chapters and code examples.

For cases where you do want to impose an ordering on a non-Comparable class that does not have a natural ordering, you can always supply a Comparator instance to help sort it.

  • 3
    There is even more fun when you start thinking about compareTo with Exception (which isn't an abstract class and thus would have implemented it meaning aNullPointerException.compareTo(anUnsupportedFlavorException) would have... meaning? –  May 07 '15 at 02:43
  • 10
    _all objects can be checked for equality_ In Java yes, but in general no. There are some examples of objects where equality comparison doesn't make sense (not even reference equality) - e.g. singletons. There could be interfaces (abstract classes) like ValueEquality and ReferenceEquality. It might not even be so bad idea ... – qbd May 07 '15 at 09:08
  • 6
    "all objects can be checked for equality. If nothing else, one can see if two objects exist at the same location in memory (reference equality)." -- since we do have `==` for the latter, this has a hollow ring to it. Disregarding the redundant default, one can find valid reasons *not* to assume `equals` on all classes, since not all types may support an equivalence relation. – Raphael May 07 '15 at 12:55
  • 1
    Singletons can obviously be compared for equality. Since there is only one, a singleton will always be compared to itself, so it is always equal. (It may also be compared to nil and then it compares not equal). – gnasher729 May 07 '15 at 13:25
  • 1
    Importantly, the equals() method compares an object to any other object (or null). Obviously, your singleton X is not the same as your singleton Y. But you could put both of them into a HashSet (of Objects), so the equals() method must be able to compare them. – user3294068 May 07 '15 at 13:38
  • @qbd Why can't singletons be checked for equality? – Ben Aaronson May 07 '15 at 14:12
  • 2
    @BenAaronson Well, they could be checked for equality, it just doesn't make sense. Another example is stateless service objects - why would you check their equality? Value objects shouldn't be checked for reference equality, only for value equality. That's why it would make sense to model these objects without implementing Equality interfaces, thus forbidding clients to do what essentially doesn't make sense. – qbd May 07 '15 at 14:55
  • @qbd: For any pair of object references X and Y, the question "Do X and Y identify equivalent objects" does not become meaningless if X and Y identify objects of unrelated types. Instead, the answer to the question is simply "no". I do think Java erred in only having one means of asking about one equivalence relation when most applications need two, and in not having a means of telling collections how equivalence of encapsulated items relates to their own equivalence, but equivalence is an important concept that should be fundamental to a framework. – supercat May 07 '15 at 18:53
  • 4
    Two examples of types where it's not sensible to define equality: streams (e.g. lazy potentially infinite lists or infinite precision numbers) and functions. The former has the problem that establishing equality may require comparing infinitely. Deciding if two functions are equal is undecidable. Asking if two instances of these types exist in the same memory location is 1) not very useful and 2) allows clients to write code that's sensitive to what should be implementation details. Today I may give you a new instance of the same infinite list each time you ask, tomorrow I may memoize it. – Doval May 07 '15 at 20:26
  • @Doval Comparing streams via reference equality makes sense, even if it is a useless thing to do. In Java, comparing functions for equality really is nonsense because functions/methods cannot be compared anyway because they are not objects in the context of this question. –  May 07 '15 at 20:31
  • 6
    @Snowman The fact that it's useless combined with the fact that exposes implementation details is reason enough not to allow it. Pretty much every "value-based" class in Java 8 has some boilerplate saying "We're not responsible for what happens if you use `==`" because how those classes are instantiated is an implementation detail but the language makes it impossible to hide. You could say that anyone comparing two `Integer`s by reference is an idiot, but allowing the comparison to begin with is dumber still. – Doval May 07 '15 at 20:43
  • Thread's natural ordering can be the starting time – Display Name May 08 '15 at 08:32
  • 1
    @SargeBorsch could be. That is one way to order threads. Just like one way to order humans is by birth date and time. Or we (just like threads) could be ordered by name. What is more natural? Very subjective. This is why _some_ objects have a natural ordering (`Comparable`) while we can impose arbitrary ordering on any object (`Comparator`). –  May 08 '15 at 12:45
8

The JLS §4.3.2 defines the class object in the following way:

4.3.2. The Class Object

The class Object is a superclass (§8.1.4) of all other classes.

All class and array types inherit (§8.4.8) the methods of class Object, which are summarized as follows:

  • The method clone is used to make a duplicate of an object.

  • The method equals defines a notion of object equality, which is based on value, not reference, comparison.

  • The method finalize is run just before an object is destroyed (§12.6).

  • The method getClass returns the Class object that represents the class of the object.

  • A Class object exists for each reference type. It can be used, for example, to discover the fully qualified name of a class, its members, its immediate superclass, and any interfaces that it implements.

    The type of a method invocation expression of getClass is Class<? extends |T|> where T is the class or interface searched (§15.12.1) for getClass.

    A class method that is declared synchronized (§8.4.3.6) synchronizes on the monitor associated with the Class object of the class.

  • The method hashCode is very useful, together with the method equals, in hashtables such as java.util.Hashmap.

  • The methods wait, notify, and notifyAll are used in concurrent programming using threads (§17.2).

  • The method toString returns a String representation of the object.

So, that's why equals is in Object but compareTo is in a separate interface. I would speculate that they wanted to keep Object as minimal as possible. They probably figured that nearly all Objects would need equals and hashCode (which is really just a form of equality testing) but not all objects would need to have a concept of ordering, which is what compareTo is used for.

durron597
  • 7,590
  • 9
  • 37
  • 67
  • I guess there could theoretically be an interface `Equitable` but if `Object` implemented it, then every class would be an `Equitable`. At that point, is there a difference? In effect not really, in complexity yes. – Captain Man May 07 '15 at 13:56
  • 1
    @CaptainMan In .Net, `object` has `Equals(object)`, just like in Java, but there's also the `IEquatable` interface. Though the primary reason for it to exist is to avoid boxing when `T` is a value type, which is not possible in Java. – svick May 07 '15 at 16:53
  • hashCode is ***not*** a form of equality testing, because there are hash collisions. if A and B are equal, they have the same hashCode, but if A and B have the same hashCode, this does not mean they are equal! – Josef May 08 '15 at 08:40
  • 1
    actually, your answer would greatly benefit from switching to an older JLS (http://titanium.cs.berkeley.edu/doc/java-langspec-1.0.pdf) - it has a much better quote on why `equals` is declared in `Object` directly: `The methods equals and hashCode are declared for the benefit of hashtables such as java.util.Hashtable (§21.7)` - as Java design is backwards-compatible, Java 1.0 design choice is the actual reason for `equals` being where it is. –  May 17 '16 at 12:53
  • since the edit I've proposed will probably get rejected for being "too drastic", in case you'd want to just Ctrl+C/Ctrl+V the relevant stuff into your answer: http://pastebin.com/8c4EpLRX –  May 17 '16 at 13:10
  • http://programmers.stackexchange.com/review/suggested-edits/139025 –  May 17 '16 at 17:30
2

In addition to Snowman's excellent answer, remember that Comparable has been a generic interface for a long time. A type doesn't implement compareTo(object), it implements compareTo(T) where T is its own type. This cannot be implemented on object, since object does not know the class that will be derived from it.

object could have defined an compareTo(object) method, but this would have allowed not just what Snowman points out, a comparison between two ArrayList<T>s or between two Threads, but even a comparison between an ArrayList<T> and a Thread. That's even more nonsensical.

hvd
  • 486
  • 3
  • 9
0

Suppose I have two object references: X identifies an instance of String holding the content "George"; Y identifies instance of Point holding the coordinates [12,34]. Consider the following two questions:

  • Do X and Y identify equivalent objects?

  • Should X sort before, after, or equivalent to Y?

The fact that X and Y identify instances of unrelated types does not pose any problem when considering the first question. Objects can only be considered equivalent if their types share a common base that defines them as being equivalent; since String and Point have no such base (their only common base type regards all distinct objects as non-equivalent) the answer is simply "no".

The fact that the types are unrelated, however, poses a huge problem with regard to the second question. Some types define ordering relationships among their instances, and some ordering relationships may even extend over multiple types [e.g. it would be possible for BigInteger and BigDecimal to define comparison methods that would allow instances of either type to be ranked relative to instances of the other], but it is not possible in general to take two arbitrary instances and ask "Should X sort before, after, or equivalent to Y" and derive a total ordering. It would be possible to ask "Should X sort before, after, equivalent, or unranked with respect to Y" if objects were required to report a consistent ordering though not a total one, but most sorting algorithms require total orderings. Thus, even if all objects could implement a compareTo method if "unranked" was a valid return, such a method wouldn't be useful enough to justify its existence.

supercat
  • 8,335
  • 22
  • 28