HashMap原理分析

93 阅读2分钟

散列表

概念:一种数据结构,将key映射到映射到表中一个位置以便快速访问记录,结合数组、链表优点,高效增删改

散列表通常使用一个数组来存储数据。数组的每个位置称为一个槽

当两个不同的键通过散列函数得到相同的槽位置时,就会发生冲突。解决冲突的常见方法有开放寻址法(如线性探测、二次探测、双重散列)和链地址法(将冲突的元素链接在一起)。

缺点:额外的策略来解决哈希冲突,为了减少冲突,散列表的数组大小通常要大于存储的数据量,这可能导致空间的浪费,散列函数的选择

哈希:就是将任意长度的输入,通过hash算法都可以得到固定长度的输出,从hash值不可以退出原始数据

HashMap原理

继承体系:

image.png

底层存储结构:

image.png

Node数组默认初始化长度为16(源码中定义的常量,1左移四位),当Node数组中所有元素个数超过64,并且链表长度大于8时,链表将变成红黑树

put原理

首先构造出Node节点,通过hash计算出key的的HashCode值,然后通过扰动函数使Hash值更散列得到最终Hash值,通过路由算法(表的长度-1&Hash值 )找到在Node数组中存放的位置

扰动函数的意义:让表的长度不是很高的情况下,让HashCode的高16位也进行到路由算法的计算中

表的长度一定是2的多少次方?

当数组长度是2的幂次方时,表长度减1之后是全1,然后和其他数做与运算可以快速算出存放的索引位置

为什么引入红黑树:自平衡的二叉搜索树,就是为了防止链化过长,导致取同一个Hash值的时候遍历时间过长,链化遍历复杂度为O(n),而于红黑树来说,它的时间复杂度是O(logN)

扩容原理

只有在第一次在HashMap里面插数据的时候才会初始化,延迟初始化

负载因子,就是当Node数组长度*负载因子时,会出发扩容

对于扩容时的流程中(扩容容量翻倍),只需要判断hash&oldcap==0?保留原位置:旧位置+旧容量