Do you know Java: Beware of instanceof in equals
One of the most important methods is equals. So, it is also important how it
is implemented.
What is the real issue with instanceof and equals? Let us see an implementation
of it. First, let us introduce a simple class and its inheritant that demonstrate
the usage of equals`.
public class Mug {
private double capacity;
// ctor, setter, getter
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (!(o instanceof Mug)) {
return false;
}
Mug other = (Mug) o;
return other.capacity == this.capacity;
}
}
Then we see as:
Mug m1 = new Mug(1.2);
Mug m2 = new Mug(1.2);
System.out.println(m1.equals(m2)); // true
System.out.println(m2.equals(m1)); // true
What if there is an inheritant of Mug? How does equals work in that case?
public class PlasticMug extends Mug {
private String plastic;
// ctor, setters, getters
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (!(o instanceof PlasticMug)) {
return false;
}
PlasticMug other = (PlasticMug) o;
return other.getCapacity() == this.getCapacity() && other.plastic.equals(plastic);
}
}
As seen above, let us apply the equals on the instances of Mug and PlasticMug.
System.out.println(mug.equals(plastic)); // true
System.out.println(plastic.equals(mug)); // false
instanceof operator returns true if the type of the object is the same, or
inherited from the type on right. On the other side, instanceof never returns
true if the right operand is one of the parents of the type of the object
sitting on the left side of instanceof.
How can we fix it?
getClass() method returns the exact class literal of the object whether its
static type is Object.
The equals method of Mug. PlasticMug is similar.
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (getClass() != o.getClass()) {
return false;
}
Mug other = (Mug) o;
return other.capacity == this.capacity;
}
After changing the two implementations of equals, then the results look as
follows:
System.out.println(mug.equals(plastic)); // false
System.out.println(plastic.equals(mug)); // false
As previously said, beware of using instanceof in equals, and use getClass() method instead.
Code can be found: https://github.com/torokmark/do-you-know-java