hashMap1.7头插法及扩容
hashmap头插法是在jdk1.7之前版本中存在的。
一、什么是头插法
hashmap结构内部table表,当不同的元素hash相等的时候,在该位置table[i]形成链表,相同位置后来者插入到链表表头的位置
public V put(K key, V value) {if (table == EMPTY_TABLE) {inflateTable(threshold);}if (key == null)return putForNullKey(value);int hash = hash(key);int i = indexFor(hash, table.length);for (Entry<K,V> e = table[i]; e != null; e = e.next) {Object k;if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}modCount++;addEntry(hash, key, value, i);return null;}
for循环里头的意思是遇到相同的key,直接覆盖
不同的key,继续执行
addEntry(hash, key, value, i);
void addEntry(int hash, K key, V value, int bucketIndex) {if ((size >= threshold) && (null != table[bucketIndex])) {resize(2 * table.length);hash = (null != key) ? hash(key) : 0;bucketIndex = indexFor(hash, table.length);}createEntry(hash, key, value, bucketIndex);}
addEntry的时候检查当前元素个数有没有达到hashmap最大容量*加载因子的值,如果达到则扩容,先不看扩容,先看看在不扩容的条件下怎么实现头插法
void createEntry(int hash, K key, V value, int bucketIndex) {Entry<K,V> e = table[bucketIndex];table[bucketIndex] = new Entry<>(hash, key, value, e);size++;}
/*** Creates new entry.*/Entry(int h, K k, V v, Entry<K,V> n) {value = v;next = n;key = k;hash = h;}
createEntry新建一个Entry,不管数组table[bucketIndex]是否为空(不管table表bucketIndex位置是否已有元素),新建的Entry的next赋值为table[bucketIndex],所以当table[bucketIndex]不为空的时候,新插入的元素永远都是链表链表头的位置。完成了任何元素的put。
这里为什么要使用头插法呢?当链表中有n个元素的时候如果往链表尾部插入一个元素,需要遍历链表,时间负责度为n,头插法时间复杂度为1。
二、扩容
hashmap初始容量默认为16,当容量不够时,会自动扩容,每次扩容新容量为当前容量的2倍
resize(2 * table.length);
void resize(int newCapacity) {Entry[] oldTable = table;int oldCapacity = oldTable.length;if (oldCapacity == MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return;}Entry[] newTable = new Entry[newCapacity];transfer(newTable, initHashSeedAsNeeded(newCapacity));table = newTable;threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);}
创建一个新的2倍容量的空数组Entry[] newTable = new Entry[newCapacity];
/*** Transfers all entries from current table to newTable.*/void transfer(Entry[] newTable, boolean rehash) {int newCapacity = newTable.length;for (Entry<K,V> e : table) {while(null != e) {Entry<K,V> next = e.next;if (rehash) {e.hash = null == e.key ? 0 : hash(e.key);}int i = indexFor(e.hash, newCapacity);e.next = newTable[i];newTable[i] = e;e = next;}}}
table为原来的数组,需要把table的元素放到新的newTable中。
for循环表里table数组,(数组的每一个值都有可能是链表)
while遍历链表,将链表中的所有元素放到新的newTbale中,当链表元素e.next为空的时候结束当前位置链表遍历。
那有怎么保证newTable中的元素形成链表结构,并且也符合头插法的方式插入呢
e.hash 还是原来的hash,可以改变重新计算hash,默认不重新计算hash,hash不用重新计算,但是Entry e在新的newTable的位置还是要重新计算的,因为newCapacity,变成了原来的2倍,位置基本都会改变。
int i = indexFor(e.hash, newCapacity);
计算得到新的位置:i
这是不管newTable[i]是否有值
将此时的Entry e 的next赋值为newTable[i],即时
e.next = newTable[i];
然后newTable[i] = e
这就相当于在newTable[i]的链首插入进来Entry e
hashMap1.7头插法及扩容相关推荐
- 【图解】HashMap1.7 头插法造成死循环的原因
1.概述 HashMap1.7当中,扩容的时候,采用的是头插法转移结点,在多线程并发的情况下会造成链表死循环的问题. 2.图解 假设有两个线程,线程1和线程2,两个线程进行hashMap的put操作, ...
- hashmap1.7头插法造成死循环的原因分析
关于这个问题,网上的说法真是五花八门,怎么说的都有,我也不知道他们是不是真的理解.我是对照源码一步步分析的,目前为止,我只看到一个视频和我的观点是一样的,大家不同意的可以自己去扒源码自己分析一遍,至少 ...
- Java HashMap1.7头插法扩容时出现循环链表 1.8换成尾插法
HashMap扩容流程 单线程下扩容 多线程下扩容 当前顺序: 用Key值表示键值对,顺序为5->9->11->null 插入节点流程 next=node.next;//存储下一个需 ...
- Hashmap扩容时出现循环链表(jdk1.8把头插法换成了尾插法的原因)
参考:https://blog.csdn.net/sinat_39410753/article/details/106242573 1.容量计算 容量的阈值=容量*加载因子 2.扩容容量 扩容的容量大 ...
- HashMap面试题 头插法、尾插法、hash冲突、数组扩容、ConcurrentHashMap
文章目录 HashMap 的数据结构? HashMap 的工作原理? HashMap 的 table 的容量如何确定?loadFactor 是什么?该容量如何变化?这种变化会带来什么问题? 数组扩容的 ...
- HashMap在JDK1.7版本头插法实现解析
HashMap在JDK1.7版本头插法实现解析 先解释下何为头插法.大家都知道HashMap在JDK1.7版本的数据结构为数组+链表这样的形式.而头插法说的就是在往HashMap里面put元素时,此时 ...
- 【Java】JDK 7 HashMap 头插法在并发情况下的成环问题
CONTENT 问题描述 成因详解 总结 Reference 问题描述 JDK 7 的 HashMap 解决冲突用的是拉链法,在拉链的时候用的是头插,每次在链表的头部插入新元素.resize() 的时 ...
- jdk1.7HashMap链表头插法导致的死循环
jdk1.7的HashMap的源码分析参考我之前整理的HashMap,之前也有整理头插法导致的死循环,这里再整理一下.参考连接 扩容的核心源码如下: void transfer(Entry[] new ...
- 面试官:说说java1.7HashMap头插法导致死循环的问题
HashMap头插法会导致死循环问题 大家天天都说Java1.7Hashmap头插法会导致死循环问题 可是大家知道为什么嘛? 下面我们来详细讲解一下全过程: 首先hashmap头插法导致死循环问题是在 ...
最新文章
- Word2Vec 使用总结
- 关于c语言的fib的程序总结,C语言程序设计试卷及答案
- python 用户认证_python基于mysql的用户认证
- Java学习第三天160818 表单 框架 下拉列表等
- jquery 前台分页插件总结(1 前台假分页 2 后台分页)
- 慢查询优化,我终于在生产踩到了这个坑!!
- HP服务器集成 iLO 端口的配置
- 数学建模学习交流论文写作课件
- Latex绘制三线表
- 简单因式分解100道及答案_初二数学压轴题100题
- weblogic安装与部署项目
- 基于GD32MCU程序远程升级IAP设计思路
- sci论文发表的难度高吗
- 程序员转正述职报告_程序员个人述职报告范文4篇(整理版)
- 快速使用ros小乌龟教程——ROS初体验
- node学习记三之vue与安装的模块(d3\echarts\jquery)
- 未来智能酒店里 智能管家将24小时待命
- C7:如何使用JEPG Simulation进行ColorTuning?
- HTML5及CSS3基础知识(持续更新)
- 线阵相机的线扫描速率的计算方法
热门文章
- ViewPager+Fragment实现页卡切换
- Android左右滑动控件实现开关的切换效果
- 苹果计算机安装应用软件,Mac苹果电脑怎么安装软件 Mac苹果电脑安装软件新手教程...
- ubuntu 8.04玩魔兽争霸
- Power BI 矩阵总计放表第一列
- 《2022中国RPA采购指南》报告正式发布
- EMBA课程小记(4)——“半面创新”课程体会
- 移动光猫+路由器+移动电视盒子iptv 家庭组网方案——光猫路由改桥接
- 企业网络及应用层安全防护技术精要(Part I)
- uniapp小程序运行正常,app运行报cid unmatched at view.umd.min.js