Ohoh equality checking in the face of inheritance. That's EXTREMELY hard to get right and rather long to describe.
The correct solution isn't as straight forward as one would think, so please go read this - that should clear up all your questions. If not feel free to ask again :)
Edit: So as a short summary of the above link: An equality method should fulfill the following properties:
- It is reflexive: for any non-null value x, the expression x.equals(x) should return true.
- It is symmetric: for any non-null values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
- It is transitive: for any non-null values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
- It is consistent: for any non-null values x and y, multiple invocations of x.equals(y) should consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
- For any non-null value x, x.equals(null) should return false.
To guarantee that this works, we need to specify another method: public boolean canEqual(Object other)
. This method should return true if the other object is an instance of the class in which canEqual is (re)defined, false otherwise.
In other words the method must always be overwritten if we overwrite equal()
itself. The implementation itself is trivial, a short example:
class Foo {
public boolean canEqual(Object other) {
return other instanceof Foo;
}
// equals implementation, etc.
}
The equals method itself must always first check if the given object canEqual itself, e.g. something along the lines of other.canEqual(this) && restOfComparison
.
Short example of a class extending the above Foo:
class Bar extends Foo {
public boolean equals(Object other) {
if (other instanceof Bar) {
Bar that = (Bar)other;
return that.canEqual(this) && otherStuff;
}
return false;
}
public boolean canEqual(Object other) {
return other instanceof Bar;
}
}