Let's say I have a simple class that represents a game tile, called Tile:
public class Tile {
public final int x;
public final int y;
public final int plane;
public Tile(int x, int y, int plane) {
this.x = x;
this.y = y;
this.plane = plane;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof Tile) {
Tile other = (Tile) obj;
return other.x == x && other.y == y && other.plane == plane;
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(x, y, plane);
}
}
Being a responsible citizen, I implemented the hashCode method to make sure hash codes of equivalent objects are equal, per contract of equals. Then I was thinking, for any two Tile objects that have the same values for the x, y, and plane fields, the hash codes - as they should - will be equal. So why not just use that to check if objects are equivalent, rather than individually comparing the values of the fields?
More explicitly, why not replace:
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof Tile) {
Tile other = (Tile) obj;
return other.x == x && other.y == y && other.plane == plane;
}
return false;
}
with simply:
@Override
public boolean equals(Object obj) {
return obj == this || obj != null && obj.hashCode() == hashCode();
}
Part of me feels that this is bad practice. This almost feels like circular reasoning. However, I cannot think of a valid, practical reason as to why this would be a bad practice.
In short: is it appropriate to use the result of hashCode to determine the result of equals?
No. Think of it as follows: there are 2^32 * 2^32 * 2^32 = 2^96 different possible Tiles, for each combination of three ints.
There are only 2^32 possible hashCodes.
So for any given Tile there will be 2^64 different possible Tiles with the same hash code.
In short: hash codes are not unique. Many objects will happen to have the same hash code even though they're not equal.
(In general, always remember that return 0; is a valid implementation of hashCode().)
See the contract of hashCode():
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results.
Two "equal" objects should have the same hash code.
Two "unequal" objects can have the same hash code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With