HashMap底层分析_put添加元素
图片不够清晰?,点https://gitmind.cn/app/flowchart/f0c3178602查看高清图片,密码:7818
HashMap通过put()方法添加元素(List集合通过add()方法添加元素),元素插入的索引位置通过hash()计算key的hash值确定,插入的具体实现在putVal()方法中。
//当两个结点的key相同,则新节点的value会覆盖旧结点的value,并且会将旧的value返回
public V put(K key, V value) {return putVal(hash(key), key, value, false, true);
}
计算hash值,并返回该hash值。
static final int hash(Object key) {int h;//如果key为null,则返回0,反之则返回key的hash值(key的hashCode值与key的hashCode值的高16位进行^异或运算得到的值)return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Node节点元素插入的具体代码都在putVal()方法内。(这个方法很重要,建议搭配上面的流程图来看,一定要搞清楚,看完后自己可以用GitMind也画一个流程图,这样印象会很深刻)
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {//Node数组 Node<K,V>[] tab; Node<K,V> p; //p是临时结点int n, i; //数组长度,索引// 数组未初始化或者长度为0,进行扩容if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 确定元素存放在哪个桶中,桶为空,新生成结点放入桶中if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);// 桶中已经存在元素 : p(指向链表头节点)else {Node<K,V> e; K k;// 比较桶中第一个元素p与要插入元素的key是否相等,key相等则此次put为覆盖操作if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))// 将第一个元素赋值给e,用e来记录e = p;// key不相等且头节点p为红黑树结点,则此次put为向红黑树中插入节点else if (p instanceof TreeNode)//将节点添加到红黑树上e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);// key不相等;头节点p为链表结点,则此次put为向链表中插入节点(树化发生在此处)else {//遍历链表,有两种情况下才会跳出循环for (int binCount = 0; ; ++binCount) {//第一种:已经遍历到尾部,在尾部插入新结点跳出。(因节点数量+1 判断是否需要树化)/** 节点的下一个节点为null,说明遍历到了链表的最后一个节点,* 将当前遍历到的最后一个节点的next指向新插入节点*/if ((e = p.next) == null) {//在尾部插入新结点p.next = newNode(hash, key, value, null);//判断是否需要树化/*** 如果链表长度大于8,则需要树化**注意,binCount是从0开始的,并且执行这一步之前添加了一个新节点,此时链表长度为1+7+1=9.* 所以不要看着binCount >= TREEIFY_THRESHOLD - 1 = 7,就以为链表长度>=7就会红黑树化了*/if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st//并且数组长度>=64,则链表就会树形化(这些会在treeifyBin()方法中实现)treeifyBin(tab, hash);//跳出循环break;}// 第二种:e指向的节点与要插入节点的key相同,此次put为覆盖操作if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))//跳出循环break;//用于遍历桶中的链表,与前面的e = p.next组合,可以遍历链表p = e;}}//如果新节点不为空if (e != null) { // existing mapping for key//记录e的valueV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)//用新值替换旧值e.value = value;afterNodeAccess(e);//返回旧值return oldValue;}}++modCount;//添加新结点后,要判断数组的使用长度,如果达到临界值,那么数组就会扩容if (++size > threshold)resize();afterNodeInsertion(evict);return null;
}
插入节点元素时,遍历链表,当p.next ==null时,这个节点就是链表的尾节点,然后就可以通过修改尾节点元素的next指针指向,让next指针指向要插入的节点元素,这样我们的节点就顺利插入链表尾部了。 if
语句中调用了newNode()方法,这个方法会根据传入的hash,key,value等参数,创建一个Node节点对象,并返回这个节点对象,这个节点对象就是我们要插入的节点元素
//节点的next指向为null,则该节点是尾节点
if ((e = p.next) == null) {//让最后一个节点next指针指向要插入的节点元素p.next = newNode(hash, key, value, null);//...此处省略...
}
根据传入的hash,key,value等参数,创建一个(non-tree)Node节点对象,并返回这个节点对象
// Create a regular (non-tree) node
Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {return new Node<>(hash, key, value, next);
}
Node<K,V>是一个静态内部类,实现了Map接口中的内部Entry接口
static class Node<K,V> implements Map.Entry<K,V> {final int hash; //hash值final K key; //keyV value; //valueNode<K,V> next; //指向下一个结点的next指针,(这是个单向链表,所以只有next指针,没有pre指针)Node(int hash, K key, V value, Node<K,V> next) {this.hash = hash;this.key = key;this.value = value;this.next = next;}
}
HashMap底层分析_put添加元素相关推荐
- HashMap底层原理分析
HashMap底层分析 一.JDK1.8之前 二.JDK1.8后 1.JDK1.8中的涉及到的数据结构 1.1 位桶数组 1.2 数组元素Node 一.JDK1.8之前 JDK1.8 之前 Has ...
- java map原理_Java HashMap底层原理分析
前两天面试的时候,被面试官问到HashMap底层原理,之前只会用,底层实现完全没看过,这两天补了补功课,写篇文章记录一下,好记性不如烂笔头啊,毕竟这年头脑子它记不住东西了哈哈哈.好了,言归正传,今天我 ...
- HashMap 底层源码细致分析
JDK集合HashMap 底层源码细致分析 前言 提示:对于初始 HashMap 的小伙伴来说,不推荐直接硬啃,建议先看一下如下几个视频教程之后再回头好好理解.(一遍看不懂则反复看,一小块一小块的找对 ...
- HashMap底层原理分析(put、get方法)
1.HashMap底层原理分析(put.get方法) HashMap底层是通过数组加链表的结构来实现的.HashMap通过计算key的hashCode来计算hash值,只要hashCode一样,那ha ...
- 深度解剖HashMap底层原理
HashMap底层原理 写在前面 JDK1.7版本--HashMap java.1.7源码分析 new一个HashMap实例的存储流程图如下: API常用方法 API中重要的变量 第一步:申明一个Ha ...
- JDK1.7中HashMap底层实现原理
JDK1.7中HashMap底层实现原理 一.数据结构 HashMap中的数据结构是数组+单链表的组合,以键值对(key-value)的形式存储元素的,通过put()和get()方法储存和获取对象. ...
- java 的HashMap底层数据结构
HashMap也是我们使用非常多的Collection,它是基于哈希表的 Map 接口的实现,以key-value的形式存在.在HashMap中,key-value总是会当做一个整体来处理,系统会根据 ...
- HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别(转)
HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别 文章来源:http://www.cnblogs.com/beatIteWeNerverGiveU ...
- hashMap 底层原理+LinkedHashMap 底层原理+常见面试题
1.源码 java1.7 hashMap 底层实现是数组+链表 java1.8 对上面进行优化 数组+链表+红黑树 2.hashmap 是怎么保存数据的. 在hashmap 中有这样一个结构 Node ...
最新文章
- 在Data Collector中使用TensorFlow进行实时机器学习
- oracle数据倾斜优化,Hive数据倾斜优化 - ericquan8的个人页面 - OSCHINA - 中文开源技术交流社区...
- SSM环境+jquery+ajax 实现批量文件上传并预览后,同时上传文件和数据 校验图片后缀是否合法 文件大小是否超限
- 银行代码就是银行行号吗?
- 2020年ESA中国区10m地表覆盖数据的镶嵌、裁剪与分省数据分享
- 柠檬班高级性能测试13期这个课老师讲的很细腻需要了解见正文
- IDEA 快捷键 代码上移一行 下移一行 快捷键 try catch 块 快捷键
- Java最新面试题及答案
- rem、em、px、rpx、vw、vh、%等
- 相位相关计算两张图片的平移量
- python 'NoneType' object has no attribute '_root'
- 本地docker不能登录远程harbor服务器,error response from daemon,error parsing http 403 response body
- 电子制造ERP管理系统在仓库管理中的应用
- 大话设计模式 第十一章 迪米特法则 小黑小白在开车
- bat批处理循环执行adb命令,非科班面试之旅
- RST切换成AHCI无法正常进入windows(装双系统Ubuntu)
- 爱我专业主题黑板报计算机,我爱我班主题黑板报
- Python学习交流群、python学习群、python技术交流群
- 温度控制模块项目总结
- 关于websocket做即时通信功能
热门文章
- 「雕爷学编程」Arduino动手做(20)—水银开关模块
- 关于移动端滚动穿透问题的解决
- 潭州课堂25班:Ph201805201 django框架 第五课 自定义简单标签,包含标签,模型类创建,梳理类创建 (课堂笔记)...
- Java中的变量数据类型补充
- 无边框模式对话框,设置鼠标拖动
- WPF的ComboBox 数据模板自定义
- FLASH得到MYSQL数据
- [Comet OJ - Contest #7 D][52D 2417]机器学习题_斜率优化dp
- MongoTemplate 使用aggregate聚合查询
- 微信小程序 自定义顶部状态栏