Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bit-shifting in Effective Java hashCode() implementation

Tags:

I was wondering if someone could explain in detail what

(int)(l ^ (l >>> 32));

does in the following hashcode implementation (generated by eclipse, but the same as Effective Java):

private int i; private char c;  private boolean b; private short s; private long l; private double d; private float f;  @Override public int hashCode() {     final int prime = 31;     int result = 1;     result = prime * result + i;     result = prime * result + s;     result = prime * result + (b ? 1231 : 1237);     result = prime * result + c;     long t = Double.doubleToLongBits(d);     result = prime * result + (int) (t ^ (t >>> 32));     result = prime * result + Float.floatToIntBits(f);     result = prime * result + (int) (l ^ (l >>> 32));     return result; } 

Thanks!

like image 865
Mark Pope Avatar asked May 13 '10 14:05

Mark Pope


People also ask

How does hashCode () method work in Java?

Simply put, hashCode() returns an integer value, generated by a hashing algorithm. Objects that are equal (according to their equals()) must return the same hash code. Different objects do not need to return different hash codes.

What is the default implementation of hashCode in Java?

In Java, hashCode() by default is a native method, which means that the method has a modifier 'native', when it is implemented directly in the native code in the JVM. Used to digest all the data stored in an instance of the class into a single hash value i.e., a 32-bit signed integer.

How is the hashCode implemented in object Java?

Basically the default implementation of hashCode() provided by Object is derived by mapping the memory address to an integer value. If look into the source of Object class , you will find the following code for the hashCode. public native int hashCode();


2 Answers

Basically it XORs the top 32 bits of a long with the bottom 32 bits. Here's an exploded version:

// Unsigned shift by 32 bits, so top 32 bits of topBits will be 0, // bottom 32 bits of topBits will be the top 32 bits of l long topBits = l >>> 32;  // XOR topBits with l; the top 32 bits will effectively be left // alone, but that doesn't matter because of the next step. The // bottom 32 bits will be the XOR of the top and bottom 32 bits of l long xor = l ^ topBits;  // Convert the long to an int - this basically ditches the top 32 bits int hash = (int) xor; 

To answer your comment: you have a long value which has to be converted into an int to be part of the hash (the result has to only be 32 bits). How are you going to do that? You could just take the bottom 32 bits - but then that means changes in only the top 32 bits would be ignored, which wouldn't make it a very good hash. This way, a change in a single bit of input always results in a change of a single bit of the hash. Admittedly you can still get collisions easily - change both bits 7 and 39, for example, or any other pair of bits 32 positions apart - but that's bound to be the case, given that you're going from 264 possible values to 232.

like image 59
Jon Skeet Avatar answered Oct 01 '22 06:10

Jon Skeet


It takes a 64 bit number, splits it half, and xors the two halves together (essentially).

like image 35
corsiKa Avatar answered Oct 01 '22 05:10

corsiKa