Solution to aa68: Symmetric equality testing
See code at solutions/code/tutorialquestions/questionaa68
This online tutorial illustrates a very clever trick. We equip Point
with a method, canEqual
, which tells us the conditions an object must satisfy for it to even be considered
as being equal
to a Point
. In the case of a Point
, the condition is that the given object
should be an instance of Point
. Thus we implement canEqual
as follows:
public boolean canEqual(Object that) {
return that instanceof Point;
}
Now in the equals
method of Point
, we test whether the incoming object is an instance of Point
as before
(except that to avoid duplication, we do this by calling canEqual
). Then we cast the incoming object to a Point
, and
ask whether it can equal the Point
on which equals
is being invoked. If this test succeeds, we conclude by comparing
fields as before.
Checking canEqual
in both directions is what allows us to restore the symmetric property that we require equals
to satisfy. In ColouredPoint
we override canEqual
, strengthening the criterion to being an instance of
ColouredPoint
, not just of Point
:
@Override
public boolean canEqual(Object that) {
return that instanceof ColouredPoint;
}
Note that it is usually bad practice to override a method and make no reference to super
. This is an exception (though note that if the overridden version of canEqual
returns true, the superclass version would be guaranteed to do the same).
The implementation of equals
in ColouredPoint
is now adapted analogously to how equals
was adapted for Point
: we check that the ColouredPoint
on which equals
is being invoked canEqual
the incoming object. We then cast the incoming object to a ColouredPoint
and test superclass equality. Due to the way we implemented equals
in Point
, this superclass call will test whether this ColouredPoint
canEqual
the ColouredPoint
on which equals
is being invoked. Finally, we compare on the colour
fields, as before.
The crucial missing property that canEqual
has added is that if we compare a plain old Point
with a ColouredPoint
we are guaranteed to get the result false
. Thus the asymmetry identified in question 5235 cannot occur.