I would look at the code for String and HashMap, as they have a low collision rate and do not use % and process negative numbers.
From source for string
public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
From source for HashMap
/** * Retrieve object hash code and applies a supplemental hash function to the * result hash, which defends against poor quality hash functions. This is * critical because HashMap uses power-of-two length hash tables, that * otherwise encounter collisions for hashCodes that do not differ * in lower bits. Note: Null keys always map to hash 0, thus index 0. */ final int hash(Object k) { int h = 0; if (useAltHashing) { if (k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h = hashSeed; } h ^= k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
Since the HashMap always has a power of 2, you can use
hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length);
and
static int indexFor(int h, int length) { return h & (length-1); }
Using & much faster than % and returns only positive numbers, since the length is positive.
Peter Lawrey Dec 11 '12 at 18:05 2012-12-11 18:05
source share