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