赞
踩
① 负载因子:默认为 0.75,表示 HashMap 存储的元素数到达 HashMap 散列数组长度的 0.75 时就进行扩容
负载因子
也可以认为是存储的元素有多少个,当然,散列数组中的元素个数越多,内存利用率就告,但是hash冲突的概率也会很高
负载因子越大,散列数组的内存利用率越高,但哈希冲突概率也越高,查询效率相对降低;
负载因子越小,散列数组的内存利用率越低,但哈希冲突概率越低,查询效率相对较高
② 散列数组:HashMap 通过分离链表法解决哈希冲突的问题,在散列数组中存储的就是链表中的一个个头节点
③ K-V 键值对:K-V 键值对以 Node 节点的方式进行存储,Node 继承自 Map.Entry,包含 Next 指针,Key,Value 和 hash
④ threshold:就是 负载因子 * 数组容量(其实就是数组元素到达总数组的多少才进行扩容)
⑤ size:HashMap 中当前存储的节点数
需要注意:HashMap 允许插入键为 null 的键值对。
但是因为无法调用 null 的 hashCode() 方法,也就无法确定该键值对的桶下标
,只能通过强制指定一个桶下标来存放。HashMap 使用第 0 个桶存放键为 null 的键值对。
① 再哈希:首先通过key获取到hashCode值,然后这个hash值要与数组的长度-1
进行与运算来确定该值应该放到数组那个位置。
② 检查散列数组是否为空,若为空,初始化散列数组,数组容量将会初始化为16
③ 若 Key 的 HashCode 对应的散列数组位置上节点为空,则直接将新节点加入
④ 若不为空,比较链表的头节点 Key 与 put Key 是否相等,先比较 hashcode,再比较(== || equals),若相等,进行更新,若不相等,顺着链表按同样的逻辑进行比较
⑤ 若是 1.8 的HashMap,会先判断链表的头节点是否是 TreeNode,若是,则按照红黑树的逻辑进行插入
⑥ 1.7 的 HashMap 中,若遍历完链表仍未找到 Key 相同的节点,则将新节点加入到链表头,会造成并发扩容的死链问题,1.8 中,将头插法改为了尾插法,解决了死链问题,但并发环境下的其他基本问题,如更新丢失等,仍然没有解决
1.8 以前一直采用头插法的是由于计算机的局部性原理,即一个最近被访问过的对象,很有可能很快会被再访问到,基于该假设,在头节点插入,可以有效的提高查询的效率,在发生并发问题时,完全可以使用 concurrent map来解决
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。