qno*_*oid 23 java hash hashmap
有人可以向我解释静态HashMap #hash(int)方法吗?
生成均匀分布的哈希值背后的理由是什么?
/**
* Applies a supplemental hash function to a given hashCode, 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.
*/
static int hash(int h) {
// 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);
}
Run Code Online (Sandbox Code Playgroud)
一个例子可以让它更容易消化.
澄清 我知道运算符,真值表和按位运算.我真的无法真正解码实现或评论.甚至背后的推理.
pol*_*nts 16
>>>是逻辑右移(无符号扩展)(JLS 15.19移位运算符),并且^是按位异或 - (JLS 15.22.1整数位运算符).
至于为什么要这样做,文档提供了一个提示:HashMap使用两个幂的长度表,并通过屏蔽高位并仅取其哈希码的低位来散列键.
// HashMap.java -- edited for conciseness
static int indexFor(int h, int length) {
return h & (length-1);
}
public V put(K key, V value) {
int hash = hash(key.hashCode());
int index = indexFor(hash, table.length);
// ...
}
Run Code Online (Sandbox Code Playgroud)
因此,hash()尝试将相关性带到更高的位,否则将被屏蔽掉(indexFor基本上丢弃较高位h并且仅取较低k位length == (1 << k)).
对比方式Hashtable(应该没有两个幂的长度表)使用密钥的哈希码.
// Hashtable.java -- edited for conciseness
public synchronized V get(Object key) {
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % table.length;
// ...
}
Run Code Online (Sandbox Code Playgroud)
通过执行更昂贵的%操作(而不是简单的位掩码),性能对Hashtable较低位的分布较差的哈希码较不敏感(特别是如果table.length是素数).