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
instanceofto 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
floatordoublefield we need to callFloat.compareandDouble.comparethe method, if the field is object filed call theequalsmethod 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.