HashMap 类
1、是 Map 接口使用频率最高的实现类
2、无序(添加、取出顺序不一致)、无索引,不保证映射顺序
3、维护一个哈希表:数组 + 单向链表 + 红黑树
4、key、value 可以是任意引用数据类型
5、key 不允许重复,key 只允许一个 null,value 允许重复,value 允许多个 null
6、添加 key - value,若集合有相同 key,原 value 会被新 value 替换
7、线程不安全,没有 synchronized,没有实现同步互斥
底层
1、无参构造器
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
(1)负载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
(2)链表红黑树化及扩容的临界值
static final int TREEIFY_THRESHOLD = 8;
(3)链表红黑树化及扩容的临界值
static final int MIN_TREEIFY_CAPACITY = 64;
(4)红黑树退化为链表的临界值
static final int UNTREEIFY_THRESHOLD = 6;
(5)扩容的临界值
int threshold;
(6)记录哈希表中有效节点数
transient int size;
(7)哈希数组
transient Node<K,V>[] table;
2、添加 key - value、扩容机制
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
(1)得到待添加 key 的 hash 值,散列函数如下,若 key 为 null,hash 值为 0,否则 (h = key.hashCode()) ^ (h >>> 16)
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
(2)若 table 是 null 或大小为 0,第一次扩容至 16
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
(3)根据 key 的 hash 值,算出 key 的索引值:(table.length - 1) & hash,p 指向该索引的位置,即链表的头节点 / 红黑树的根节点
(4)p 为 null,在该索引位置直接创建 Node,添加 key - value
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
(5)p 不为 null,p.hash 值与待添加 key 的 hash 值相等,且 p.key 与待添加 key 是同一对象 / 待添加 key 不为 null 且和 p.key 经 equals 方法比较后结果一致,则原 key 对应的原 value 被新 value 替换
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
(6)判断 p 是否为红黑树,若 p 是红黑树,就调用 putTreeVal 添加
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
(7)若 p 不是红黑树,从第二个 key 进行 for 循环与待添加 key 比较,即重复步骤(5)
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
(8)若链表该中的 key 有相同,则原 key 对应的原 value 被新 value 替换;若都不符合,则 key - value 添加到链表尾
(9)添加后,判断该链表是否达到 8 个节点,若链表 >= 8 个节点,调用 treeifyBin 方法,若 table 数组容量 >= 64,将该链表进行红黑树化
(10)若添加 key - value 后,++size(有效节点数)>= threshold = 当前 table 容量 * 0.75(负载因子),则 table 新容量 = 原容量 * 2
if (++size > threshold)
resize();
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战