HashMap的底层原理分析
- 关键成员变量/常量:
- Node<k,v>[] table:HashMap底层存储数组
- Float loadfactor :加载因子,无参初始化时为默认加载因子
- Int threshold:扩容阈值,一般为table数组的长度*加载因子(0.75)
- Int Size:集合的长度(kv键值对的个数)
- final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 默认数组长度16
- final int MAXIMUM_CAPACITY = 1 << 30;最大数组长度
- final float DEFAULT_LOAD_FACTOR = 0.75f;默认加载因子
- final int TREEIFY_THRESHOLD = 8;转树形时链表的最小长度
- final int MIN_TREEIFY_CAPACITY = 64;转树形时数组的最小长度
- put元素时底层原理:
- 通过扰动函数计算所存放元素中key的hash值
- 添加元素前判断之前的数组table是否为空,如果是,则进行扩容
具体扩容原理如下:
扩容后:table数组长度由开始的0,变成16,扩容阈值从0变成了12
- 通过table数组长度-1&hash的方法,确定要添加元素所存放的位置,并判断此位置是否已有元素,如果没有则可直接存放
- 如果此位置已经有元素,通过hash和equals判断要添加元素的key值和已经在此位置元素的key值是否相同,如果key值不同,则对原位置元素的value进行覆盖
- 如果key值相同,则说明发生了hash冲突,此时将要添加的元素以node节点的形式连到原位置元素的后面,先判断是否为树形节点,如果不是则按单向链表的形式进行连接
- 后续添加元素,如果仍然在此位置发生哈希冲突,就继续往最后添加的元素后面连接,用p.next==null判断,在此过程中重复(4)的过此,即判断后续添加的元素与前面的元素的key值是否相同,相同则覆盖原元素的value,不相同则进行连接
- 如果同一个位置的连接的元素超过8个,同时table数组的长度小于64,则需进行扩容,当同一个位置的连接的元素超过8个同时数组长度超过64,则改为红黑树的形式连接要添加的元素
此时的扩容机制为数组长度按两倍扩容,扩容阈值也按两倍扩容
- 还有一种情况也需要扩容,即数组中的元素个数大于扩容阈值,此时会进行扩容
此时的扩容机制和上面相同,即数组长度和扩容阈值都按两倍扩容!
总结: hashmap集合put元素时的底层原理:
(1) 使用hash计算元素存储到数组的位置i=(数组长度-1)%hash,如果此处没有位置,则直接存储
(2) 如果此处有元素,判断key地址或内容是否相同,如果是则覆盖原元素中的value值
(3) 如果key不同则说明发生了hash冲突,此时元素已node节点形式连接到原位置元素的后面,先判断是否为树形,如果是,则按照树形结构添加,如果不是则按照单向链表添加,已p==null作为判断,将新增元素添加到链表末尾