Subsection 5.7.3 Overriding the equals Method
The equals method defined in Object and thus inherited by all classes only considers two object references equivalent if they refer to exactly the same object. But we saw in Unit 2 that the String class provides an equals method that considers two String objects equivalent if they have the same characters in the same order, even if they are actually different objects. How does that work?
It is because the String class has overridden the equals method it inherited from Object to provide a definition of equality that makes more sense.
As we saw in section 9.3 a class can override inherited methods by providing a method with the same method signature (method name, parameter types, and return type). String has done that with equals so when we compare String objects with equals that new method will be called instead of the inherited one.
Activity 5.7.3.
Try to guess what this code will print out before running it.
However, overriding equals is a bit more involved than overriding toString. While the toString method is only required to produce a reasonable human-readable String representation of an object, equals has to meet a more complex set of requirements in order to be useful.
You will not be expected to write your own equals method on the AP exam but it’s worth looking at what those requirements are and how to satisify them. There are five requirements described in the Javadocs for equals in Object that a properly implemented equals must satisfy:
Equality is reflexive, meaning an object will be equals to itself: o.equals(o) is true.
Equality is symmetric: o1.equals(o2) returns the same value as o2.equals(o1).
Equality is transitive: if o1.equals(o2) and o2.equals(o3) then o1.equals(o3).
Equality is consistent: o1.equals(o2) always returns the same value assuming the objects are not modified.
No object is equal to null: o.equals(null) is always false.
The other way to look at these requirements is as guarantees that are made to you as a user of equals. If you look at it that way, these requirements are quite nice. Imagine how much harder it would be to use the String equals method if you couldn’t rely on the fact that s1.equals(s2) is necessarily the same as s2.equals(s1)!
So even though the Java compiler can’t force you to implement equals correctly, if you ever do want to override it, it’s important that you do. Let’s look at what’s involved.
We’ll write a class Word which represents a word in a particular language. We want two Word objects to be considered equals if and only if they are spelled the same and come from the same language. The latter requirement is because sometimes different languages have words that are spelled the same but with different meanings such as “pie” which in English is a tasty baked treat and in Spanish is what we call a “foot” in English.
Activity 5.7.4.
Try to guess what this code will print out before running it. Click on the CodeLens button to step forward through the code and watch the memory.
The basic recipe for writing your own equals method, is:
Use the public boolean equals(Object other) method signature. Make sure the parameter type is Object, not the class you are defining.
Check of this == other to quickly return true when comparing an object to itself.
Use instanceof to check if other is an instance of this class and return false if not.
Cast other to the current class.
Finally compare this object’s attributes to the other object’s with == for primitive types like int and double and equals for reference types. If you need to compare multiple attributes && together the comparisons of the individual attributes since two objects should only be equal if all the attributes match.
Note that the requirements on equals make it almost impossible to correctly override it in a subclass of a class that has already overridden the Object version. To see why, imagine if we made a subclass of Word, ClassifiedWord and added another attribute, partOfSpeech.
If we override equals in the ClassifiedWord to only consider two ClassifiedWord objects equals if their spelling, language, and part of speech match, that will break the symmetry since regularWord.equals(classifiedWord) will invoke the equals from Word which will only compare the spelling and language of the word but classifiedWord.equals(regularWord) will return false assuming the equals in ClassifiedWord checks that other is an instanceof
ClassifiedWord. In general you should only provide an overridden equals method in one class in a class hierarchy.