1.5.4.1 Overriding equals
Keywords: current

Next: 1.5.5 Helper Methods, Packages, Up: 1.5.4 Inheritance and the Previous: 1.5.4 Inheritance and the

### 1.5.4.1 Overriding `equals`

As an example of inheritance, consider the method

    public boolean equals(Object o);

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).

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-except on the argument `null`, which is treated as a special case. In particular, for all non-`null` `x` and `y`, `x.equals(y)` iff `y.equals(x)`. If the argument to `equals` is `null`, then the Java API specification stipulates that `equals` must return `false`.1.5If 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.5.2 above. The following code for the definition of `equals` in the `Cons` does not work in general!

      public boolean equals(Object o) {
        return (o != null) && (o instanceof Cons) &&
          (first == ((Cons)o).first) && rest.equals(((Cons)o).rest);
      }

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 o) {
        return (o != null) && (o instanceof ExtCons) &&
          (first == ((ExtCons)o).first()) && rest.equals(((ExtCons)o).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`.

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 o) {
        return (o != null) && (o.getClass() == Cons.class) &&
          (first == ((Cons)o).first) && rest.equals(((Cons)o).rest);
      }

Finger Exercise Load the sample program `intList` into the DrJava Definitions pane. Override the definition of `equals` for both `Empty` and `Cons` to match the definition of the mathematical notion of equality on lists of integers, i.e., two lists are equal iff they contain exactly the same elements in exactly the same order. Try evaluating a substantial set of test cases for your new method in the Interaction pane of DrJava.

Next: 1.5.5 Helper Methods, Packages, Up: 1.5.4 Inheritance and the Previous: 1.5.4 Inheritance and the