翻下源码 , HashMap#putVal , 里面的逻辑 , 先校验计算出来的 , 数组tab的下标 , i=(n-1)&hash是否冲突了 , 不冲突就新增节点 , 冲突的情况 , 转链表或者红黑树
if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);6、Jdk8中HashMap的put操作
- put方法的核心流程
- 根据hashcode计算数组的下标
- 对应下标数组为空的情况 , 新增节点
- 否则就是哈希冲突了 , 如果桶使用链表节点 , 就新增到链表节点尾部 , 使用了红黑树就新增到红黑树里
ok , 还是跟一下put源码:
public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node[] tab; Node p; int n, i;// 第1次新增 , 初始数据resizeif ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 判断是否出现hash冲突if ((p = tab[i = (n - 1) & hash]) == null)// hash不冲突 , 新增节点tab[i] = newNode(hash, key, value, null);else { // 哈希冲突的情况 , 使用链表或者红黑树处理Node e; K k;// 存在重复的键的情况 , key和hash都相等if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))// 将旧的节点对象赋值给新的ee = p;else if (p instanceof TreeNode) // 使用了红黑树节点// 将节点放到红黑树中e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);else { // 链表的情况// 无限循环for (int binCount = 0; ;binCount) {// 一直遍历 , 找到尾节点if ((e = p.next) == null) {// 将新节点添加到尾部p.next = newNode(hash, key, value, null);// 节点数量大于8 , 转为红黑树if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);// 跳出循环break;}// 也是为了避免hashCode和key一样的情况if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;// 重新赋值 , 用于链表的遍历p = e;}}// 桶中找到的key、hash相等的情况 , 也就是找到了重复的键 , 要使用新值替换旧值if (e != null) { // existing mapping for key// 记录e的值V oldValue = https://www.shwenmu.com/wenda/e.value;if (!onlyIfAbsent || oldValue == null)// 用新值替换旧值e.value = value;// 访问后回调afterNodeAccess(e);// 返回旧值return oldValue;}}// 记录修改次数modCount;// size大于threshole , 进行扩容if (size> threshold)resize();// 回调方法afterNodeInsertion(evict);return null;} 然后是怎么转换为红黑树的?红黑树的知识相对比较复杂final void treeifyBin(Node[] tab, int hash) {int n, index; Node e;// MIN_TREEIFY_CAPACITY值为64 , 也就是说数组长度小于64是不会真正转红黑树的if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)// 扩容方法resize();// 转红黑树操作else if ((e = tab[index = (n - 1) & hash]) != null) {// 红黑树的头节点hd和尾节点t1TreeNode hd = null, tl = null;do {// 构建树节点TreeNode p = replacementTreeNode(e, null);if (tl == null)// 新节点p赋值给红黑树的头节点hd = p;else {// 新节点的前节点就是原来的尾节点t1p.prev = tl;// 尾部节点t1的next节点就是新节点tl.next = p;}tl = p;} while ((e = e.next) != null);// 让数组的节点执行新建的树节点 , 之后这个节点就变成TreeNodeif ((tab[index] = hd) != null)hd.treeify(tab);}} 7、HashMap的扩容机制这个知识点是HashMap中的一个重点之一 , 也是一个比较难的问题7.1、什么时候需要扩容?当hashMap中元素个数超过threshold , threshold为数组长度乘以负载因子loadFactor , loadFactor默认是0.75f
7.2、什么是HashMap的扩容?resize这个方法是HashMap的扩容方法 , 是比较耗时的 。HashMap在扩容时 , 都是翻两倍 , 比如16的容量扩大到32, 。HashMap进行扩容的方法是比较巧妙的 , 扩容后 , 与原来的下标(n-1)&hash相对 , 其实只是多了1bit位 。扩容后节点要么是在原来位置 , 听起来好像很懵 , 所以还是认真看下面的分析:
推荐阅读
- 王水是由什么组成的混合物 王水溶金原理
- 小米11隔空充电什么原理-小米11隔空充电技术原理介绍
- 时钟电路的原理和作用
- 消防智能化的图片,智能消防系统原理
- 点读笔原理 点读笔学英语有效果吗
- 微波炉加热原理 微波炉加热原理是什么
- 怠速电机工作原理是什么
- GPS卫星信号由哪几部分组成及作用 gps天线原理拆解
- DVD刻录机的工作原理 刻录机是什么东西
- 除湿机原理 工业除湿机工作原理
