Don't Let Hibernate Steal Your Identity
Subject:   Instanceof in equals()
Date:   2006-09-14 09:58:33
From:   jbrundege
Response to: Instanceof in equals()

I don't agree with the idea that you should never use instanceof in an equals() method. You have to test the class of the given object somehow, and the two techniques are instanceof and getClass(). instanceof allows subclasses to inherit the equals() method, but with the danger that someone will override equals in a subclass which breaks the symmetric property of equals(). The alternative is to use getClass(), which only compares the runtime types and does not consider subclasses equal to their superclasses. This has the inverse danger when the author of the subclass intends to inherit equals() and is surprised to find that their subclass can never be equal to an instance of the parent class. This is a somewhat contentious issue. Josh Block has written about it here:

The point of Liskov's Substitution Principle is that people who subclass must be careful to honor all the contracts of the parent class. My intention of the contract of PersistentObject was that the id is a unique identifier of object identity and should thus be used as the sole indicator of identity in the equals() method. The only way to break symmetry is to break this contract. Since my intent was that there is never a need a to override equals(), I could have made it final as well.

An alternative would be to do the comparison with getClass(), which changes the contract to: object identity is defined as the id AND the class of the object. This works but is somewhat less flexible. Either way an author of subclasses must understand these contracts and make sure their subclasses honor them.