How and why to write custom equals methods in Java
Why override standard equals?
By default, every Java object has an
equals(Object o) method which is inherited from the
Object class. The implementation of this
equals method compares objects using their memory locations, meaning that two objects are only considered equal if they actually point to the exact same memory location and are thus really one and the same object.
If you want to define equality in such a way that two objects can be considered equal even if they are not really the exact same object in the exact same memory location, you will need a custom
The requirements for a good
- Reflexivity: every object is equal to itself
- Symmetry: if a is equal to b, then b is also equal to a
- Transitivity: if a is equal to b and b is equal to c, then a is also equal to c
- Consistency: if a is equal to b right now, then a is always equal to b as long as none of their state that is used in the
equalsmethod has been modified
- Non-nullity: an actual object is never equal to
Not properly overriding the
equals(Point) does not properly override
equals(Object) because the signature doesn't match.
- In the first assertion, we are calling a method with signature
equals(Object)on an object with compile-time type
Pointdoes not implement a method with that signature, the best match is the
equals(Object)method inherited from
- In the second assertion, we are calling a method with signature
equals(Point)on an object with compile-time type
Objectdoes not have an
equals(Point)method, the best match at compile time is its
equals(Object)method. And, because
Point(the run-time type of
pointObject) does not override that method, the actual implementation that gets called is still the one defined in
hashCode, and default implementation is likely to return different hash codes for different objects (not same memory location)
x also changes the hash code, which means that the hash bucket where the set now looks for the point is different from the hash bucket where the point ended up based on its initial hash code.
Simple decent implementation
hashCode methods are pretty much what Eclipse generates by default
Dealing with subclasses
Allowing subclasses to be equal to superclasses
equals method using
this.getClass() returns different class for objects of different classes!
Most IDEs have option to do this when generating
Subclasses including additional state in
What if some subclasses of
Point have additional info to consider when determining if objects are equal?
What if we want to include the color in the
equals method so that a
ColorPoint(1, 1, Color.RED) is not equal to a
ColorPoint(1, 1, Color.BLUE)?
If we want this, we have to accept that a
ColorPoint will never be equal to any
Point. The reason for this is transitivity (see above). If we want to say that
ColorPoint(1, 1, Color.RED) and
ColorPoint(1, 1, Color.BLUE) are both equal to
Point(1, 1) , then transitivity would imply that they are also equal to each other. That is exactly what we didn't want here.
This could be seen as a violation of the Liskov substitution principle
The hard, but potentially more correct way
- passes all of the previous tests
- still allows subclasses of
Pointthat do not include additional state to be equal to a
The easy way
Drawback: objects can only be equal if they are or exactly the same class
- Let your IDE generate your
hashCode) methods for you, using
- Either make your class
finalor make your
Note that the two options outlined in step 2 have different effects:
- Making your class
finalprevents any issues with subclasses by simply not allowing subclasses for your class.
- Making your
finalprevents subclasses from overriding your
hashCodemethods and including additional state in them.
In cases where this is not sufficient (you want subclasses to include additional state in their
equals method), consider using the solution involving the
canEqual method or the simpler solution using
getClass if you’re ok with subclass instances never being equal to superclass instances.
Better alternative to hand-written
equals tests: the EqualsVerifier library by Jan Ouwens.
Uses reflection to inspect class and test its
hashCode methods with 100% coverage.