2

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?

Martin Tuskevicius
  • 2,590
  • 4
  • 29
  • 46

3 Answers3

6

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().)

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
2

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.

Matthieu
  • 2,736
  • 4
  • 57
  • 87
1

Because 2 objects may have same hash function, but may not be equal.

Think of it this way. In a hash table, the object's hash code is computed to find the bucket in which the object will go. The bucket may have multiple objects with same hash code. It is the equals method which will find the object from the list (collection) of objects in the bucket.

Java equals() and hashCode() Contract

In the above mentioned link, go to section "Problem caused by hashCode()" and have a look at 2nd point.

Here is a snippet of it

1) If two objects are equal, then they must have the same hash code.

2) If two objects have the same hash code, they may or may not be equal.

Master Chief
  • 2,520
  • 19
  • 28