Why do we need to override the equals method
Q: When to override the equals
method?
A: If the class not override it and the object identity is merely not enough for equality.
A right implementation of equals
makes the instance object to serve as map keys or set elements with predictable and desirable behavior
equals
method is characteristic:
- reflexive: an object should equal itself.
- symmetric: if object A equals object B, object B should equal with object A as well
- transitive: if A equals B, B equals C, so A should equal C.
- consistency: the same result will return no matter how many times you run it.
And one more important characteristic that only exists in the OOP world.
Lisov substitution principle says that any important property of a type should also hold for all its subtypes so that any method written for the type should work equally well on its subtypes.
What does that mean?
For example:
class A {
int size;
}
class B extends A {
Color color;
}
A a = new A(1);
B b = new B(1, Color.RED);
a.equals(b) // should return true
Extend instantiable class and add a value component to it violate the transitive rule easily.
Like java.util.Timstamp
extend from java.util.Date
and add nanoseconds field.
One common mistake this that do the null checking and getClass() to compare in the equal method. That will make the equals method not able to have the Lisov substitution characteristic.
Not necessary to null checking in the equals
method. Simply cast it to the object we want so we could have the accessor to it.
public boolean equals(Object o) {
if (!(o instanceof MyType)) {
return false;
}
}
Conclusion
High quality equals
method:
- Use the == operator to check if the argument is a reference to this object: Performance optimization
- Use
instanceof
to check if the arg has the correct type. No need to do the null check. - Cast argument to correct type.
- Check if a file of the arg matches the corresponding field: if
float
ordouble
field we need to callFloat.compare
andDouble.compare
the method, if the field is object filed call theequals
method recursively. To avoid the possibility ofNullPointerException
, usingObjects.equals(Object, Object)
After writing the equals
method.
Is it symmetric? Is it transitive? Is it consistent?
Use the AutoValue
framework to write hashCode
and equals
more easily.
Top comments (1)
In Java, don't forget to override the hashCode method as well, otherwise maps won't treat them as equal.