本文源码基于JDK1.8.0_45。

 1 final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
 2     Node<K,V>[] tab; Node<K,V> p; int n, i;
 3     //延迟初始化数组,这是HashMap中最基础的数据结构
 4     if ((tab = table) == null || (n = tab.length) == 0)
 5         n = (tab = resize()).length;
 6     //数组中hash对应位置没有元素,就把当前元素放入作为头节点,结束put的流程
 7     //计算哈希值在数组中的位置时,使用了数组容量-1与哈希值做与运算的方式,保留了哈希值的低位数据作为数组下标
 8     if ((p = tab[i = (n - 1) & hash]) == null)
 9         tab[i] = newNode(hash, key, value, null);
10     else {
11         Node<K,V> e; K k;
12         //如果头节点的Key值相等,则头节点是目标元素
13         if (p.hash == hash &&
14             ((k = p.key) == key || (key != null && key.equals(k))))
15             e = p;
16         //如果头节点是一个树节点,表示该数据结构是红黑树,则调用红黑树的方法查找或添加目标元素
17         else if (p instanceof TreeNode)
18             e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
19         //最后判断该数据结构为链表,并在链表中查找Key相等的元素
20         else {
21             for (int binCount = 0; ; ++binCount) {
22                 //链表中不存在该Key值,将新值添加到链表末端,如果链表长度达到阈值需要转换为红黑树
23                 //treeifyBin方法中生成红黑树有一个条件,如果数组长度太小,只会先执行扩容操作,当数组长度达到生成树的阈值时才会执行生成红黑树的逻辑
24                 if ((e = p.next) == null) {
25                     p.next = newNode(hash, key, value, null);
26                     if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
27                         treeifyBin(tab, hash);
28                     break;
29                 }
30                 //如果在链表中找到目标节点,则中断循环
31                 if (e.hash == hash &&
32                     ((k = e.key) == key || (key != null && key.equals(k))))
33                     break;
34                 p = e;
35             }
36         }
37         //如果HashMap中不存在目标元素,前面的代码逻辑已经将元素添加进了Map中
38         //如果HashMap中存在目标元素,则视情况选择是否更新旧的值
39         if (e != null) { // existing mapping for key
40             V oldValue = e.value;
41             if (!onlyIfAbsent || oldValue == null)
42                 e.value = value;
43             afterNodeAccess(e);
44             return oldValue;
45         }
46     }
47     /**
48     * 如果新增了节点,最后还需要更新节点的数量,如果超过阈值则需要对HashMap进行数组扩容,并重新分配节点所在的数组
49     * 扩容的原因在于数组的长度一定,当元素的哈希值碰撞时,会以链表或红黑树的形式存储,元素的数量太多会影响HashMap的读写效率
50     * 因此需要对数组进行扩容,使元素更加分散,减少链表的长度或红黑树的高度。
51     */
52     ++modCount;
53     if (++size > threshold)
54         resize();
55     afterNodeInsertion(evict);
56     return null;
57 }

代码中涉及的resize方法、红黑树的实现、链表转换成红黑树的逻辑等将在系列其他文章介绍。

转载于:https://www.cnblogs.com/lwpimis/p/10572235.html

HashMap源码分析1:添加元素相关推荐

  1. Java类集框架 —— HashMap源码分析

    HashMap是基于Map的键值对映射表,底层是通过数组.链表.红黑树(JDK1.8加入)来实现的. HashMap结构 HashMap中存储元素,是将key和value封装成了一个Node,先以一个 ...

  2. HashMap源码分析(转载)

    一.HashMap概述 HashMap基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了不同步和允许使用 null 之外,HashMap  ...

  3. 在参考了众多博客之后,我写出了多达三万字的HashMap源码分析,比我本科毕业论文都要精彩

    HashMap源码分析 以下代码都是基于java8的版本 HashMap简介 源码: public class HashMap<K,V> extends AbstractMap<K, ...

  4. hashmap源码分析及常用方法测试_一点课堂(多岸学院)

    HashMap 简介 底层数据结构分析 JDK1.8之前 JDK1.8之后 HashMap源码分析 构造方法 put方法 get方法 resize方法 HashMap常用方法测试 感谢 changfu ...

  5. 查询已有链表的hashmap_源码分析系列1:HashMap源码分析(基于JDK1.8)

    1.HashMap的底层实现图示 如上图所示: HashMap底层是由  数组+(链表)=(红黑树) 组成,每个存储在HashMap中的键值对都存放在一个Node节点之中,其中包含了Key-Value ...

  6. 源码分析系列1:HashMap源码分析(基于JDK1.8)

    1.HashMap的底层实现图示 如上图所示: HashMap底层是由  数组+(链表)+(红黑树) 组成,每个存储在HashMap中的键值对都存放在一个Node节点之中,其中包含了Key-Value ...

  7. Map接口总结与HashMap源码分析

    Map接口 1.Map,用于保存K-V(双列元素) 2.Map中的Key Value可以是任意引用分类型的数据,会封装到HashMap的Node对象中 3.Map的key不允许重复.原因和HashSe ...

  8. HashMap 源码分析与常见面试题

    文章目录 HashMap 源码分析 jdk 1.7 内部常量 静态内部类 Holder 类 构造方法 put 过程 put 整体流程图 jdk 1.8 增加的常量 Node 类 Hash 值计算的变化 ...

  9. HashMap源码分析

    文章目录 简介 继承关系 存储结构 源码分析 属性 Node节点 TreeNode HashMap 构造方法 put 添加方法 待更新 简介 在我们使用数据存储的时候都会有数据结构这种东西,但是传统的 ...

  10. JDK7中HashMap源码分析

    文章目录 JDK7中的HashMap 一.JDK7中HashMap源码中重要的参数 二.JDK7中HashMap的构造方法 三.JDK7中创建一个HashMap的步骤 四.JDK7中HashMap的p ...

最新文章

  1. nutch如何发布插件
  2. 对IsUnderPostmaster变量初步学习
  3. RabbitMQ支持的消息模型
  4. Django-5.1 模型层 单表操作
  5. Oracle select 基础查询语句 day02
  6. 如何优雅的激怒C/C++程序员
  7. 用户账号系统(python)
  8. 使用frp进行内网穿透的实例
  9. Python-爬取我去图书馆座位编码
  10. 学会这2招,不用设计师,一样能做出精美炫酷的可视化大屏模板
  11. Python_study_day_1_while_if
  12. 福州大学计算机报录比2019,2019-2020福州大学报录比波动分析:2020年调剂难度加大...
  13. 用户控件中图片路径问题(用户控件、图片路径) ,ResolveUrl
  14. ajax 详解(GET,POST方式传输以其封装)
  15. VBoxGuestAdditions.iso下载
  16. 想你的风还是吹到了长沙
  17. 跑步机上的精彩人生——Linus大神传奇
  18. Android Notification 详解——基本操作
  19. linux 从samba拷贝,提升samba复制速度,树莓派外接硬盘读取从40M到110M(2020-11-15更新)...
  20. Could not load the Qt platform plugin “xcb“ 问题解决

热门文章

  1. PHP扩展开发-01:第一个扩展
  2. vsftp本地用户,虚拟用户,匿名用户同时工作
  3. 由浅入深:自己动手开发模板引擎——置换型模板引擎(二)
  4. ASP.NET中防止页面多次加载的IsPostBack属性
  5. Fibonacci(斐波纳契)数列各种优化解法
  6. Android: BaseAdapter 实现分页
  7. Android ViewPager多页面滑动切换以及动画效果---换view
  8. linux命令awk
  9. STM32中的timers中断处理函数
  10. 设计模式:单例模式之静态内部类