which is defined in the class Object, the superclass of all Java classes. Any Java class that is defined without a designated superclass is an immediate subclass of the Object class. In the class Object, equals is defined to mean Object identity. Two object references are identical if and only if they refer to exactly the same object (produced by a particular new operation).public boolean equals(Object o);
For some classes, identity is the appropriate definition for equality, but for many others it is not. In the built-in class String, the equals method is redefined to compare the sequences of characters in strings, so that copies of the same string are considered equal. The redefinition of equals only affects the class String and any subclasses that it might have. This selective form of method redefinition is called method overriding.
The overriding of the equals method is particularly delicate because the Java libraries all assume that equals defines an equivalence relation. In particular, x.equals(y) iff y.equals(x). If the class containing the overriding definition of equals can be extended (subclassed) then the coding of equals is quite subtle.
In particular, the overriding definition must confirm that the argument o belongs to exactly the same class as this. Assume that we are overriding the definition of equals in the composite class hierarchy IntList given in Section 1.6 above. The following code for the definition of equals in the Cons does not work in general!
This code can fail if Cons has a subclass ExtCons because equals can report that an instance of ExtCons is equal to an instance of Cons. Even worse, if equals is overridden in ExtCons using the same instanceof pattern,public boolean equals(Object that) { return (that instanceof Cons) && (first == ((Cons)that).first) && rest.equals(((Cons)that).rest); }
a.equals(b) does not imply b.equals(a) For example, if a is an instance of Cons and b is an an instance of ExtCons with exactly the same first and rest fields as a, a.equals(b) will be true while b.equals(a) will be false (because a instanceof ExtCons is false.public boolean equals(Object that) { return (that instanceof ExtCons) && (first == ((ExtCons)that).first()) && rest.equals(((ExtCons)that).rest()); }
The problem with the instanceof pattern for writing equals is that instanceof does not test for an exact class match. We can compare the classes of objects by using the method getClass() which is inherited by all classes from Object. This method returns an instance of the class Class representing the class of the receiver object. In addition, we can get the Class object for any specific class C, simply by typing C.class. Every class has exactly one Class object representing it. Hence, the equals method for Cons above can be rewritten:
public boolean equals(Object that) { return (that.getClass() == this.getClass()) && (first == ((Cons)that).first) && rest.equals(((Cons)that).rest); }
Finger Exercise Load your saved program IntList.java into
the DrJava Definitions window. Override the definition of equals for both Empty and Cons to match the definition
of the equal? function in Scheme on lists of integers. The
Scheme equal? function compares two lists to determine if they
contain the same sequence of elements. Try evaluating a substantial
set of test cases in the Interaction window of DrJava.
The overriding of the equals method is even more delicate if
you explicitly or implicitly uses the hashcode() method from
from class Object.1.8
If the equals method is redefined
and the hashcode() method is used, then hashcode() must
be overriden so that equal objects return the same value for
hashcode().