All equals() are not born equal
During a discussion with a colleague we started talking about the problems of equals() with inheritance. He mentioned Joshua Bloch's Effective Java book which covers this topic quit well but more or less said that this problem cannot be resolved. This was enough to get me hooked onto this problem and I came up with a solution quite fast. Afterwards I started to think about other solutions and their problems. Because all of them made sense I started to question myself if my solution was even necessary and until now I am still not sure if it does or if it is just a solution for theorists in the ivory tower. But even if it is just theory I think it is an interesting problem to talk about.
The equals() method defined in java.lang.Object has some restrictions to its implementation. Among other things it needs to symmetrical meaning that target of the method can switch places with the argument and it must yield the same result (if A is equal to B then B must be equal to A). Also it must be transient meaning that if A is equal to B and B equal to C then also A must be equal to C. There are two common ways to implement an equals() method:
- The method ensures that it only compares to instance of its own kind (class)
- The method ensures that it tests against an interface of base class and only tests if they are equal to that. An example is the AbstractList in java.util.
The first is a simple solution but breaks if someone tries to extend this class. The second solution cannot test parts of the extension of a class without breaking the rules for equals.
Before I start explaining my solution I want to come up with a use case to reason why equals() should work with inheritance. The use case is quite synthetic but it is the best model I could think of that is short and intuitive. In math you have the irrational numbers representing numbers like 1,