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头插法及扩容相关推荐

  1. 【图解】HashMap1.7 头插法造成死循环的原因

    1.概述 HashMap1.7当中,扩容的时候,采用的是头插法转移结点,在多线程并发的情况下会造成链表死循环的问题. 2.图解 假设有两个线程,线程1和线程2,两个线程进行hashMap的put操作, ...

  2. hashmap1.7头插法造成死循环的原因分析

    关于这个问题,网上的说法真是五花八门,怎么说的都有,我也不知道他们是不是真的理解.我是对照源码一步步分析的,目前为止,我只看到一个视频和我的观点是一样的,大家不同意的可以自己去扒源码自己分析一遍,至少 ...

  3. Java HashMap1.7头插法扩容时出现循环链表 1.8换成尾插法

    HashMap扩容流程 单线程下扩容 多线程下扩容 当前顺序: 用Key值表示键值对,顺序为5->9->11->null 插入节点流程 next=node.next;//存储下一个需 ...

  4. Hashmap扩容时出现循环链表(jdk1.8把头插法换成了尾插法的原因)

    参考:https://blog.csdn.net/sinat_39410753/article/details/106242573 1.容量计算 容量的阈值=容量*加载因子 2.扩容容量 扩容的容量大 ...

  5. HashMap面试题 头插法、尾插法、hash冲突、数组扩容、ConcurrentHashMap

    文章目录 HashMap 的数据结构? HashMap 的工作原理? HashMap 的 table 的容量如何确定?loadFactor 是什么?该容量如何变化?这种变化会带来什么问题? 数组扩容的 ...

  6. HashMap在JDK1.7版本头插法实现解析

    HashMap在JDK1.7版本头插法实现解析 先解释下何为头插法.大家都知道HashMap在JDK1.7版本的数据结构为数组+链表这样的形式.而头插法说的就是在往HashMap里面put元素时,此时 ...

  7. 【Java】JDK 7 HashMap 头插法在并发情况下的成环问题

    CONTENT 问题描述 成因详解 总结 Reference 问题描述 JDK 7 的 HashMap 解决冲突用的是拉链法,在拉链的时候用的是头插,每次在链表的头部插入新元素.resize() 的时 ...

  8. jdk1.7HashMap链表头插法导致的死循环

    jdk1.7的HashMap的源码分析参考我之前整理的HashMap,之前也有整理头插法导致的死循环,这里再整理一下.参考连接 扩容的核心源码如下: void transfer(Entry[] new ...

  9. 面试官:说说java1.7HashMap头插法导致死循环的问题

    HashMap头插法会导致死循环问题 大家天天都说Java1.7Hashmap头插法会导致死循环问题 可是大家知道为什么嘛? 下面我们来详细讲解一下全过程: 首先hashmap头插法导致死循环问题是在 ...

最新文章

  1. Word2Vec 使用总结
  2. 关于c语言的fib的程序总结,C语言程序设计试卷及答案
  3. python 用户认证_python基于mysql的用户认证
  4. Java学习第三天160818 表单 框架 下拉列表等
  5. jquery 前台分页插件总结(1 前台假分页 2 后台分页)
  6. 慢查询优化,我终于在生产踩到了这个坑!!
  7. HP服务器集成 iLO 端口的配置
  8. 数学建模学习交流论文写作课件
  9. Latex绘制三线表
  10. 简单因式分解100道及答案_初二数学压轴题100题
  11. weblogic安装与部署项目
  12. 基于GD32MCU程序远程升级IAP设计思路
  13. sci论文发表的难度高吗
  14. 程序员转正述职报告_程序员个人述职报告范文4篇(整理版)
  15. 快速使用ros小乌龟教程——ROS初体验
  16. node学习记三之vue与安装的模块(d3\echarts\jquery)
  17. 未来智能酒店里 智能管家将24小时待命
  18. C7:如何使用JEPG Simulation进行ColorTuning?
  19. HTML5及CSS3基础知识(持续更新)
  20. 线阵相机的线扫描速率的计算方法

热门文章

  1. ViewPager+Fragment实现页卡切换
  2. Android左右滑动控件实现开关的切换效果
  3. 苹果计算机安装应用软件,Mac苹果电脑怎么安装软件 Mac苹果电脑安装软件新手教程...
  4. ubuntu 8.04玩魔兽争霸
  5. Power BI 矩阵总计放表第一列
  6. 《2022中国RPA采购指南》报告正式发布
  7. EMBA课程小记(4)——“半面创新”课程体会
  8. 移动光猫+路由器+移动电视盒子iptv 家庭组网方案——光猫路由改桥接
  9. 企业网络及应用层安全防护技术精要(Part I)
  10. uniapp小程序运行正常,app运行报cid unmatched at view.umd.min.js