美文网首页
HashMap如何计算Entry在桶中的下标?

HashMap如何计算Entry在桶中的下标?

作者: 汪和呆喵 | 来源:发表于2018-12-10 09:51 被阅读0次

    我们知道HashMap内部包含了一个 Entry 类型的数组 table。

    transient Entry[] table;

    Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶(bucket),一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值相同的 Entry。

    那么是如何计算Entry在桶中的位置的呢?

    HashMap中的代码如下:

    int hash = hash(key);
    int i = indexFor(hash, table.length);
    

    1 计算 hash 值

    final int hash(Object k) {
        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }
    
        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);
    }
    public final int hashCode() {
        return Objects.hashCode(key) ^ Objects.hashCode(value);
    }
    

    2 取模

    static int indexFor(int h, int length) {
        return h & (length-1);
    }
    

    这个位运算等同于:hash % length

    是不是乍一看看不懂呢? 来解释一下:

    令 x = 1<<4,即 x 为 2 的 4 次方,它具有以下性质:

    x : 00010000
    x-1 : 00001111
    令一个数 y 与 x-1 做与运算,可以去除 y 位级表示的第 4 位以上数:

    y : 10110010
    x-1 : 00001111
    y&(x-1) : 00000010
    这个性质使 y & (x - 1)和 y 对 x 取模效果是一样的:

    y : 10110010
    x : 00010000
    y%x : 00000010

    我们知道,位运算的代价比求模运算小的多,因此在进行这种计算时用位运算的话能带来更高的性能。

    总结:HashMap确定桶下标的最后一步是将 key 的 hash 值对桶个数取模:hash%capacity。
    如果能保证 capacity 为 2 的 n 次方,那么就可以将这个操作转换为位运算。
    在平时的开发中我们也可以利用这个特性,对一些算法运算的效率进行优化。

    相关文章

      网友评论

          本文标题:HashMap如何计算Entry在桶中的下标?

          本文链接:https://www.haomeiwen.com/subject/dbzlhqtx.html