HashMap#hash(int)方法的说明

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并且仅取较低klength == (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是素数).

  • @Thilo,默认初始=`11`,调整大小是`int newCapacity = oldCapacity * 2 + 1;`,所以他们正在积极避免两个的力量,以充分利用昂贵的`%`操作。 (2认同)