深入理解Java之HashMap —— 02

生之智慧,在于摒弃不必要之事。若要最大限度成就真正重要之事,切忌贪多求全,事事应允。

1. HashMap的灵魂

HashMap的核心操作都是依靠着hash()展开的,在去看HashMap的操作之前,首先先了解一下hash()。

1.1 hash()

key的哈希值就是自身的hashCode的高16位和低16位进行异或运算得到的。

	static final int hash(Object key) {
        int h;
        // h >>> 16 右移16位,高位补0,取出高16位
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
1.1.1 这样设计的目的?

哈希表的容量被设计为2的N次方,则当某个key的hashCode()值 > table.length,则高位就不会参与到hash的计算。通过hashCode的高16位异或低16位,这样让高位也能参与到hash的计算当中,从而降低hash冲突的风险。


2. HashMap的精髓

下面问题的重要性不言而喻…

2.1 key 为null的hash值?

通过hash()方法,我们看到当key == null 时,其hash值为0。从而保证了key为null只能有一个

2.2 如何确定桶下标?

这里需要我们注意的是:

HashMap中的桶下标是通过 (n-1)& hash 来计算的,而不是取模运算(hash%n)来计算。

2.3 确定桶下标为什么采用位运算而不是取模运算?

  1. 从运算时间上来讲,位运算的效率远远好于取模运算

2.4 位运算如何保证下标不越界呢?

HashMap在设计上其容量必须是2的n次幂,用心良苦啊。
当 n 是 2的次幂时, n -1 的二进制表示法的尾部都是以连续1的形式来表示的。这样当(n-1)与hash进行 与运算 时,会保留hash中后x 位的1,这样就保证了索引值不会超过数组长度。

当 n 为 2的方时,满足:(n-1) & hash = hash % n

详细内容请参看:Java HashMap为什么通过(n - 1) & hash 获取哈希桶数组下标?


3. HashMap容量必须为2的幂

简而言之,还是基于效率上的考虑。即 位运算的运行效率要好于数学运算;

具体体现在:

  1. 数学运算从位运算实现。
  2. 参考2.4

这篇文章主要从HashMap的设计思路上来说明其设计之巧妙…

下一篇深入理解Java之HashMap —— 03从设计流程来探索HashMap.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章