I was just exploring different kinds of implementations to the hashCode() method. I opened up the java.lang.Integer class and found this implementation for hashCode():

public int hashCode() {
        return Integer.hashCode(value);
}

public static int hashCode(int value) {
        return value;
}

My question is, why can't the implementation be as simple as:

public int hashCode(){
    return this.value;
}

What is the need to create an additional static method to pass around the value and return the same? Am I overlooking any important detail here?

2

There are 2 best solutions below

0
On

That code does look odd when viewed on its own.

But notice that the static method java.lang.Integer.hashCode:

  • was added later, in Java 8
  • is public

The source code in Java 14 shows no comments to explain why this static method was added. Because the method is public, I presume this new static method plays a part in some new feature in Java 8, perhaps related to streams, called elsewhere in the OpenJDK codebase.

As noted in the Javadoc, the source code of the existing Integer::hashCode instance method was rewritten to call the static hashCode simply for consistency. This way there is only one place where the hash code is actually being generated. Having only one place is wise for review and maintenance of the codebase.

Making hashCode static is certainly unusual. The purpose of the hashCode method is to identify one object of that class to another for use in collections such as HashSet or HashMap. Given that we are comparing instances by the method, it makes sense for hashCode to be an instance method rather than static.

The optimizing compiler such as HotSpot or OpenJ9 is likely to inline the hashCode method calls, making moot the instance-method versus static-method arrangement in source code.

0
On

@Basil Bourque's answer covers just about everything. But he leaves open the question of why the public static void hashCode(int) was added.

The change was made in this changeset in November 2012

The title and summary for the changeset say this:

7088913: Add compatible static hashCode(primitive) to primitive wrapper classes

Summary: Adds static utility methods to each primitive wrapper class to allow calculation of a hashCode value from an unboxed primitive.

Note that the changeset does not document the motivation for the change.

I infer that one purpose of the enhancement is to avoid the application programmer having to know how the primitive wrapper classes are computed. Prior to Java 8, to compute the wrapper-compatible hash code for a primitive int, the programmer would have to have written either

  int value = ...
  int hash = ((Integer) value).hashCode();  // Facially inefficient (depending on
                                            // JIT compiler's ability to get
                                            // rid of the box/unbox sequence)

or

  int value = ...
  int hash = value;                         // Hardwires knowledge of how 
                                            // Integer.hashCode() is computed.

While the "knowledge" is trivial for int / Integer, consider the case of double / Double where the hash code computation is:

  long bits = doubleToLongBits(value);
  return (int)(bits ^ (bits >>> 32));

It seems likely that this changeset was also motivated by the Streams project; e.g. so that Integer::hashCode can be used in a stream of integers.

However, the changeset that added sum, min and max for use in stream reductions happened a couple of months after this one. So we cannot definitively make the connection ... based on this evidence.