建议先看完我这篇文章HashMap底层原理-CSDN博客
hashmap插入值的时候,是如何找到数组索引位置的呢?
例如下图左边四个连续红点,是如何在插入的时候定位到了数组下标为3的位置?
来看看put方法的源码,里面有个hash(key),这个就是定位数组位置的方法。
public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}
我们进去看看
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
h = key.hashCode()) ^ (h >>> 16),这一步就是我们想要的hash值。
put底层又对这个哈希值做了取模运算,下面看着是与运算,其实就相当于对数组长度取模。
if ((p = tab[i = (n - 1) & hash]) == null)
先通过key的hashCode方法获取第一次哈希值,再或上key右移16位,这是二次哈希,右移16位相当于除以2的16次方。得到的值再对数组长度取模,此时算出来的值对应数组下标。这就是HashMap的寻址算法,也叫扰动算法。
这么做的目的就是让hash值更均匀,减少hash冲突,不信你可以自己生成随机数,让他用这个算法,统计数组上不同位置元素个数,你会发现基本上是均匀分布的。数据均匀分布的好处就是提高查找效率,不至于一堆数据全部集中在数组一个点,查找数据还得走很长的链表或者很高的红黑树,效率都不怎么样。
而且与运算和取模效果一样是有前提的,数组长度必须是2的n次方,不然你就会看到下面的情况,两个算出来的答案不一样。
提个小问题,你知道为什么上面算数组下标要用与运算而不直接用取余(模)?
因为效率问题,与运算效率更高,计算机底层只有0和1,与运算更加快捷。