Checklist for Implementing the equals() Method – Object Comparison


Checklist for Implementing the equals() Method

Example 14.3 shows an implementation of the equals() method for version numbers. Next, we provide a checklist for implementing the equals() method.

Method Overriding Signature

The method header is

Click here to view code image

public boolean equals(Object obj)          // (1)

The signature of the method requires that the argument passed is of the type Object. The following header will overload the method, not override it:

Click here to view code image

public boolean equals(MyRefType obj)      // Overloaded.

The compiler will not complain. Therefore, it is a good idea to use the @Override annotation. Calls to overloaded methods are resolved at compile time, depending on the type of the argument. Calls to overridden methods are resolved at runtime, depending on the type of the actual object referenced by the argument. Comparing the objects of the class MyRefType that overloads the equals() method for equivalence can give inconsistent results:

Click here to view code image

MyRefType ref1 = new MyRefType();
MyRefType ref2 = new MyRefType();
Object    ref3 = ref2;
boolean b1 = ref1.equals(ref2);    // True. Calls equals() in MyRefType.
boolean b2 = ref1.equals(ref3);    // Always false. Calls equals() in Object.

However, if the equals() method is overridden correctly, only the overriding method in MyRefType is called. A class can provide both implementations, but the equals() methods must be consistent. However, there must be a legitimate reason to overload the equals() method and this practice is not recommended.

Reflexivity Test

This is usually the first test performed in the equals() method, avoiding further computation if the test is true. The equals() method in Example 14.3 does this test at (2):

Click here to view code image

return (this == obj)                                // (2)
    || (/* */);

Correct Argument Type

The equals() method of the UsableVNO class in Example 14.3 checks the type of the argument object and assigns its reference value to the local variable vno at (3) using the instanceof pattern match operator:

Click here to view code image

return (this == obj)                                // (2)
    || (obj instanceof UsableVNO vno                // (3)
        && /* Compare individual fields */);

This code also does the null comparison correctly, returning false if the argument obj has the value null.

The instanceof operator will also return true if the argument obj denotes a subclass object of the class UsableVNO. If the class is final, this issue does not arise—there are no subclass objects. The following test can be explicitly performed in order to exclude all other objects, including subclass objects:

Click here to view code image

if ((obj == null) || (obj.getClass() != this.getClass()))
  return false;

The condition in the if statement first performs the null comparison. The expression (obj.getClass() != this.getClass()) determines whether the classes of the two objects have the same runtime object representing them. If this is the case, the objects are instances of the same class.

Leave a Reply

Your email address will not be published. Required fields are marked *