What is the hashCode for a custom class having just two int properties?

Viewed 27346

In Java, I have a class that represents a point with int coordinates

public class Point {
    int x = -1;
    int y = -1;

    public Point (int xNew, int yNew) {
        x = xNew; y = yNew;
    }

    public boolean equals (Object o) {
        // no need for (o instanceof Point) by design
        return x == ((Point)o).x && y == ((Point)o).y;
    }
}

I'm using objects of class Point as keys in a HashMap and as elements in a HashSet.

What would be the best candidate for the hashCode function? I would make it double so that the left part is x and the right part is y, for example: x = 4, y = 12, then the hashCode returns 4.12. But by the implementation, it cannot be double, only int.

This is not an option:

public int hashCode() {
    // no need to check for exception parseInt since x and y are valid by design
    return Integer.parseInt(Integer.toString(x) + Integer.toString(y));
}

because values x and y can be too long, so that together they will not be converted.

8 Answers

This question is quite old, but I think the very idea will be actual as long as java exist. Let us analyze approaches above:

  1. Objects.hash(...) is fluent and clear what needs to be done, BUT it uses varargs (implicitly creating an array) and moreover, it implicitly boxes every single primitive, being passed into the method.
  2. x * 31 + y is performance-efficient: there is no boxing, no explicit or implicit array creation operations being used. BUT, it is unclear what needs to be done. Why 31, not 42? For the ones familiar with how hashing works there's no difficulties to understand such code, but what for the others? The second pitfall is that it is difficult to extend: you easily can forget to add new values into the hashing code if you, for example, wanted to go 3D and added z coordinate, because it forces you to copy-paste almost identical code many times.

I can introduce the third approach, not being mentioned in answers above:

@Override
public final int hashCode()
{
    final int[] numbers = {x, y};
    return Arrays.hashCode(numbers);
}

It uses a temporary array to hold integers being hashed, and calling Arrays.hashCode(), which is available since Java 1.5, there's also versions for other primitive types.

Pros: It is DRY, fluent and completely clear what needs to be done. It does not suffer from implicit boxing and does not uses implicit vararg. It is relatively fast and cheap. It can be easily extended by adding extra numbers into array initializer.

Cons: It is not as fast as copy-paste method. Please consider it if hash code is being called frequently.

Best regards.

Related