Java核心基础篇(三)——HashMap

一、HashMap的存储原理
1、重要成员变量
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;    // aka 16 //默认的初始化容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;        //加载因子
static final int TREEIFY_THRESHOLD = 8;                      //链表转成红黑树的阙值
static final int UNTREEIFY_THRESHOLD = 6;                //红黑树转成链表的阙值
int threshold; //扩容的阙值
transient int size; //HashMap的大小

2、存储数据结构
(1)主要使用了哈希表(数组+链表)及红黑树。红黑树是一颗近似平衡(左右子树高度一致)的二叉查找树(左节点比当前节点小,右节点比当前节点大)。
(2)元素以键值对的形式存放,并且允许null键和null值;key值唯一,无序的。
(3)HashMap是线程不安全的,多线程环境中推荐是ConcurrentHashMap。

3、整体存储过程
//public V put(K key, V value);
(1)判断数组是否空,是则使用resize()进行数组的初始化,否则执行(2);
(2)通过key的hash值找到对应数组的索引位置,判断该位置内容是否为空,空则直接存储,否则执行(3);
(3)判断数组当前位置的对象与待添加对象是否一致(hash和key),一致则直接覆盖,否则执行(4);
(4)判断当前节点是否为树节点即是否已转化为红黑树,是则直接添加,否则执行(5);
(5)对当前链表从头到尾进行查询,判断当前结点是否与待插入对象一致,是则直接覆盖;否则执行(6)
(6)链表末尾进行添加,判断当前链表结点数是否达到了要树化的阙值TREEIFY_THRESHOLD,是则调用treeifyBin()进行树化;
(7)判断HashMap的长度是否达到了要扩容的阙值,是则调用resize()进行扩容。

4、树化
//final void treeifyBin(Node<K,V>[] tab, int hash);
说明:就是链表转成红黑树的过程。
(1)判断数组长度小于默认最大数组长度64时,进行扩容;
(2)通过循环,实现将链表结点转化为树节点,同时生成双向链表;
(3)调用final void treeify(Node<K,V>[] tab)生成平衡的二叉查找树;

5、扩容
//final Node<K,V>[] resize();
说明:就是对固定长度的数组进行扩大到另一个长度(原因为随着数据越来越多,碰撞即发生哈希冲突的可能性加大),原数组的元素得重新计算位置及回填的过程(此过程比较耗性能);
(1)当原数组长度>0时,对原始数组进行扩容,长度为原来的2倍(<<1),阙值也为原来的2倍(<<1);
(2)当原数组长度<=0时,进行数组进行初始化,容量为默认16,阙值为16*.075(加载因子,即系数);
(3)原数组的元素得重新计算位置及回填

 

posted @ 2022-08-01 10:35  chance_for_ready  阅读(75)  评论(0)    收藏  举报