Deprecated: Function set_magic_quotes_runtime() is deprecated in /home/raedan/public_html/textpattern/lib/txplib_db.php on line 14
State of Flow: Overloading Java Object's equals method::journal

Overloading Java Object's equals method

Channing Walton - Sunday September 17, 2006

Overloading Object.equals() is considered a bad thing. But I was curious about a testcase that would prove why and Lance came up with one. Here it is …

Overloading Equals Example

Here is an example of overloading equals:


 public class Superclass {
  private int x;
  public Superclass(int x) {
   this.x = x;
  }
  public boolean equals(Object obj) {
   if (obj instanceof Superclass) {
    return equals((Superclass) obj);
   }
   return false;
  }
  public boolean equals(Superclass superclass) {
   return x == superclass.x;
  }
 }

The code example above looks innocent enough.

But it doesn’t work under certain circumstances. Here is a subclass of our Superclass that uses the same overloaded equals method technique:


 public class Subclass extends Superclass {
  private int y;
  public Subclass(int x, int y) {
   super(x);
   this.y = y;
  }
  public boolean equals(Object obj) {
   if (obj instanceof Subclass) {
    return equals((Subclass) obj);
   }
   return false;
  }
  public boolean equals(Subclass subclass) {
   return super.equals(subclass) && y == subclass.y;
  }
 }

A Failing Testcase

Here is a testcase that demonstrates that under some conditions the overloaded equals method will work and under others it will not. Both tests are identical except in the reference types used. In the first test references of type Superclass are used, in the second, Object :


 public class OverloadedEqualsTest extends TestCase {
  public void testEqualsWithSuperclassReferences() {
   Superclass sup = new Superclass(1);
   Superclass sub = new Subclass(1, 2);
   // This should pass, but it will fail
   assertFalse(sub.equals(sup));
  }
  public void testEqualsWithObjectReferences() {
   Object sup = new Superclass(1);
   Object sub = new Subclass(1, 2);
   // This should pass, and it does
   assertFalse(sub.equals(sup));
  }
 }

Whats Going On?

The problem in testEqualsWithSuperclassReferences() is that sub.equals(sup) is resolved by the compiler so that Superclass.equals(Superclass) is called directly. Subclass.equals(Object) is never called.

We would have to override equals(Superclass) in Subclass to make this work. Each time we add a subclass we have to override all overloaded equals(...) methods inherited transitively from all superclasses.

Not a good thing which is why overloading methods in this way is a Bad Thing in Java.