首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

HashMap 这一篇就够了

囧辉:我们现在用的都是 JDK 1.8,底层是由“数组+链表+红黑树”组成,如下图,而在 JDK 1.8 之前是由“数组+链表”组成。 ? 二狗:为什么要改成“数组+链表+红黑树”?...囧辉:计算索引位置的公式为:(n - 1) & hash,当 n 为 2 的 N 次方时,n - 1 为低位全是 1 的值,此时任何值跟 n - 1 进行 & 运算会等于其本身,达到了和取模同样的效果,...二狗:红黑树和链表都是通过 e.hash & oldCap == 0 来定位在新表的索引位置,这是为什么? 囧辉:请看对下面的例子。...因为 2 个节点在老表是同一个索引位置,因此计算新表的索引位置时,只取决于新表在高位多出来的这一位(图中标红),而这一位的值刚好等于 oldCap。...因为只取决于这一位,所以只会存在两种情况:1) (e.hash & oldCap) == 0 ,则新表索引位置为“原索引位置” ;2)(e.hash & oldCap) == 1,则新表索引位置为“原索引

1K20

详解并发下的HashMap以及JDK8的优化

JDK8中HashMap的优化 1.长链表的优化 在JDK8中,如果链表的长度大于等于8 ,那么链表将转化为红黑树;当长度小于等于6时,又会变成一个链表 红黑树的平均查找长度是log(n),长度为8的时候...在这n+1位里面,如果第1位是0,那么扩容前后这个key的位置还是在相同的位置(因为hash相同,并且余数的第1位是0,和之前n位的时候一样,所以余数还是一样,位置就一样了);如果这n+1位的第一位是1...而在JDK8中,扩容的条件只有一个,就是当前容量大于阈值(阈值等于当前hashmap最大容量乘以负载因子) HashMap在JDK7中扩容计算新索引的方法 通过transfer方法将旧数组中的元素复制到新数组...HashMap在JDK8中计算索引的方法 这个设计确实非常的巧妙,既省去了重新计算hash值的时间,也就是说1.8不用重新计算hash值而且同时,由于新增的1bit是0还是1可以认为是随机的,因此resize...但是从下图可以看出,JDK1.8不会倒置,采用的尾插法。 ? 为什么 HashMap中 String、Integer 这样的包装类适合作为 key键? ?

1.1K40
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    HashMap在JDK1.7以及JDK1.8的区别?

    1.2.插入键值对: 当调用put(key,value)时,经历以下步骤: ①计算key的哈希值(详见我的之前一篇写HashMap底层哈希值计算的文章),然后将哈希值与数组长度-1进行按位与运算,得到应该存储的数组下标索引...若与某个Entry中的key的hash值相同,则进一步通过equals方法进行比较,若equals相同则覆盖,若不同则采用头插法添加(key,value)到该数组位置。...当数组的长度大于等于threshold且要插入的地方不为null空值时,进行扩容为原来的2倍。 扩容后需要重新计算要插入元素的hash值,并且计算在新数组长度下的索引。...在第一次put元素时进行初始化和计算容量,数组长度为大于等于给定Size的最小2的次幂。 2.2.插入键值对: 与JDK1.7相同,区别是存在链表转化为红黑树的树化,以及节点插入为尾插法。...0:0.60653066 1:0.30326533 2:0.07581633 3:0.01263606 4:0.00157952 5:0.00015795 6:0.00001316 7:0.00000094

    58400

    jvm源码解析(二)HashMap

    (e.hash & newCap-1) ->(e.hash & oldCap),JDK1.8新的索引要么是j,要么是j+oldCap 头插法改尾插法(避免哈希环) 加载因子为什么是0.75 性能和容量之间平衡的结果...链表元素转换成红黑树的最小值(8) 最小树容量(64) 当hashmap有64个元素及以上,数组中某个索引的元素有8个及以上时,会链表转红黑树 注意: HashMap.put如果key在HashMap...HashMap.tableSizeFor 一开始看的时候,我觉得这是什么玩意,在玩什么呢,(因为我设置的cap值基本都是遵循了2的幂指数),后面发现,这里的操作其实是将cap-1后,最高位位1的数位后面全部数位都赋值为...,且大于等于16 newThr = oldThr 1; // double threshold } else if (oldThr > 0) // 如果老的容量小于等于零...如果不制空,比如loTail的next很可能在hiTail中(而hiTail在新HashMap中是在另一个索引下),这时候可能会出现不同索引之间的关联,造成查询的时候可能会查询到本不在这个索引位置下的Node

    39520

    外卖骑手一面,也很不容易!

    堆中节点的值都大于等于(或小于等于)其子节点的值,堆中如果节点的值都大于等于其子节点的值,我们把它称为大顶堆,如果都小于等于其子节点的值,我们将其称为小顶堆。...resize 因此,我们在扩充HashMap的时候,不需要重新计算hash,只需要看看原来的hash值新增的那个bit是1还是0就好了,是0的话索引没变,是1的话索引变成“原索引+oldCap”。...如果记录的 trx_id 值大于等于 Read View 中的 max_trx_id 值,表示这个版本的记录是在创建 Read View 后才启动的事务生成的,所以该版本的记录对当前事务不可见。...当我们在查询条件中对索引列进行表达式计算,也是无法走索引的。 MySQL 在遇到字符串和数字比较的时候,会自动把字符串转为数字,然后再进行比较。...在 WHERE 子句中,如果在 OR 前的条件列是索引列,而在 OR 后的条件列不是索引列,那么索引会失效。 Redis redis数据结构有哪些?

    25630

    freemarker常用技巧

    表达式是FreeMarker的核心功能,FreeMarker中的插值支持多种表达式。 一、直接指定值 直接指定值可以是字符串、数值、布尔值、集合及Map对象。 1....字符串 直接指定字符串值使用单引号或双引号限定。字符串中可以使用转义字符”\"。如果字符串内有大量的特殊字符,则可以在引号的前面加上一个字母r,则字符串内的所有字符都将直接输出。 2....顶层变量 所谓顶层变量就是直接放在数据模型中的值。输出时直接用${variableName}即可。 2. 输出集合元素 可以根据集合元素的索引来输出集合元素,索引用中括号包括。...三、字符串操作 1. 字符串连接 字符串连接有两种语法: (1) 使用${..}在字符串常量内插入表达式的值; (2)  直接使用连接运算符“+”连接字符串。...截取子串 截取子串可以根据字符串的索引来进行,如果指定一个索引值,则取得字符串该索引处的字符;如果指定两个索引值,则截取两个索引中间的字符串子串。

    1.8K10

    Mysql进阶优化篇02——索引失效的10种情况及原理

    物理查询优化:通过索引和表连接方式进行优化 逻辑查询优化:通过sql语句的等价代换,实现数据库查询的优化。 2️⃣数据准备 学员表插50万 条, 班级表插1万条。...这个原因还不是特别明确,可能mysql高版本中优化器又做了升级(毕竟不等于不过是等于的取反,确实可以实现优化)?笔者的mysql版本为8.2.06,如果有知道的大佬可以在评论区留言讨论。...比如可以将 INT 类型的字段,默认设置为 0。将字符串的默认值设置为空字符串(“”)。...扩展:同理,在查询中使用 not like 也无法使用索引,导致全表扫描 3.9 like 以通配符 % 开头索引失效 在使用 LIKE 关键字进行查询的查询语句中,如果匹配字符串的第一个字符为“%...3.10 OR前后存在非索引的列 在WHERE 子句中,如果在 OR 前的条件列进行了索引,而在 OR 后的条件列没有进行索引,那么索引会失效。

    1.2K10

    (1)美团面试题:Hashmap的结构,1.7和1.8有哪些区别,史上最深入的分析「建议收藏」

    (一) 真实面试题之:Hashmap的结构,1.7和1.8有哪些区别 不同点: (1)JDK1.7用的是头插法,而JDK1.8及之后使用的都是尾插法,那么他们为什么要这样做呢?...在JDK1.7的时候是直接用hash值和需要扩容的二进制数进行&(这里就是为什么扩容的时候为啥一定必须是2的多少次幂的原因所在,因为如果只有2的n次幂的情况时最后一位二进制数才一定是1,这样能最大程度减少...但是这种方式就相当于只需要判断Hash值的新增参与运算的位是0还是1就直接迅速计算出了扩容后的储存方式。 !...这里在重新进行补充两个问题:(2019-09-03) (1)为什么在JDK1.7的时候是先进行扩容后进行插入,而在JDK1.8的时候则是先插入后进行扩容的呢?...(三)为什么HashMap具备下述特点:键-值(key-value)都允许为空、线程不安全、不保证有序、存储位置随时间变化 (四)为什么 HashMap 中 String、Integer 这样的包装类适合作为

    20930

    HashMap设计思想学习

    AVL自平衡二叉树在二叉搜索树的基础上进行了优化,需要满足左右子树的高度差小于等于1,AVL树的最差查询和插入复杂度也为O(logn)。...1.7是大于等于阈值并且计算出的索引不是空位的情况下才进行扩容,而1.8是大于阈值就扩容 3. 1.7和1.8在在扩容计算Node索引时进行优化,会通过 hash & oldCap == 0 的元素留在原来位置...,否则新位置 = 旧位置 + oldCap ---- 扩容(加载)因子为何默认是 0.75f 在空间占用与查询时间之间取得较好的权衡 大于这个值,空间节省了,但链表就会比较长影响性能 小于这个值,冲突减少了...2都同时向hashmap中put一对键值对,并且key计算出来的hash值都是相同的,那么线程1和线程2同时来到判断索引位是否为空的逻辑,发现为空,填充数据,此时就存在线程2覆盖线程1的数据导致丢失数据的风险...hashCode 足够独特 字符串中的每个字符都可以表现为一个数字,称为 Si,其中 i 的范围是 0 ~ n - 1 散列公式为: S_0∗31^{(n-1)}+ S_1∗31^{(n-2)}+

    94050

    【Java数据结构和算法】013-查找:常见查找算法、顺序(线性)查找、二分查找、插值查找*、斐波那契查找*

    一、查找算法概述 1、常见的4种查找算法 ①顺序(线性)查找; ②二分查找/折半查找; ③插值查找; ④斐波那契查找(黄金分割点查找); 二、顺序(线性)查找 1、说明 对顺序无要求; 2、代码实现 package...(必须有序) 1、原理介绍 ①插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid处开始查找(对二分查找的优化); ②将折半查找中的求mid 索引的公式 , low 表示左边索引left,...] - arr[low]) ;/*插值索引*/ 对应前面的代码公式: int mid = left + (right – left) * (findVal – arr[left]) / (arr[right...这里的k值只要能使得F[k]-1恰好大于或等于n即可,由以下代码得到,顺序表长度增加后,新增的位置(从n+1到F[k]-1位置),都赋为n位置的值即可。...//为什么是k-2 //1、全部元素等于前面的元素,加上后面的元素 //2、f[k]=f[k-1]+f[k-2]

    8210

    每个前端开发者都可以开发一个属于自己的库或框架「Strve.js生态初步建成」

    我当时在想,如果我仅仅想在JS中写HTML标签,那么使用JS中的模板字符串就已经具备在字符串内写HTML标签的能力了,为什么不换一下思路,研究一下在模板字符串中写HTML标签这种更加方便直接的方案呢?...刚开始我就是从基础着手,写一串字符串,然后怎么想办法将字符串挂载到页面中。借鉴了React、Vue这些框架的思想,在页面指定一个挂载元素。...,并从模板字符串中的插值表达式中获取参数。...函数体中需要执行将改变页面状态的值,例如以下示例中的state.msg。...在Strve.js中,你可以尽情的使用JavaScript 的模板字符串,感受它独特的魅力吧!

    94840

    查找算法

    因此, 在写查找算法时, 我会将所有的东西都写在一起, 便于查找和阅读 在java中,我们常用的查找有四种: 顺序(线性)查找 二分查找/折半查找 插值查找 斐波那契查找 线性查找 思路: 如果在数组中发现满足条件的值...} } /** * 二分查找法改良,查找多个重复的元素 * 思路分析: * 1.在找到mid的索引值, 不要马上返回 * 2....向mid索引的左边扫描,将满足1000的元素的下标,加入到数组中 * 3.向mid索引的右边扫描,将满足1000的元素的下标,加入到数组中 * 4.将查找到的mid值放入数组后将这个数组返回...将折半查找中的求mid 索引的公式 , low 表示左边索引left, high表示右边索引right....这里的k值只要能使得F[k]-1恰好大于或等于n即可,由以下代码得到,顺序表长度增加后,新增的位置(从n+1到F[k]-1位置),都赋为n位置的值即可。

    77810

    Javascript 闭包与变量

    1.闭包与变量 JavaScript中的作用域链的机制引出了一个副作用,即闭包只能取得包含函数中任何变量的最后一个值。闭包所保存的是整个变量对象,而不是某个特殊的值。...1.2关于this对象 在闭包中使用this对象会出现一些问题,this对象是运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被当作某个对象的方法调用时,this等于那个对象...因此调用object.getNameFunc()()就会立即返回调用它的函数,结果就返回一个字符串。然而,这个例子返回的字符串是“The Window”,即全局name变量的值。...但是,为什么匿名函数没有取得其包含作用域(或外部作用域)的this对象呢? 每个函数在调用时,其活动对象都会自动获取两个特殊的变量:this和arguments。...我们在定义匿名函数之前,把this对象赋值给了that变量,而在定义闭包之后,闭包也可以访问这个变量,因为它们是我们在外部函数中特意声明的一个变量。

    46820

    jdk1.8 HashMap扩容机制变化「建议收藏」

    在JDK1.7及之前HashMap在扩容进行数组拷贝的时候采用的是头插法,因此会造成并发情景下形成环状链表造成死循环的问题。JDK1.8中改用了尾插法进行数组拷贝,修复了这个问题。...// 获取下一元素 Entry next = e.next; // 计算元素在新数组中的索引...int i = indexFor(e.hash, newCapacity); // 头插法 插入新数组中...= null); //直至e为空,即全部复制完毕 } } } 线程不安全问题 拷贝原数据采用的是头插法,在并发场景下,如果两个值在新数组中哈希冲突一样会出现环状链表的情形...进行一个解释说明 这个结果等于0时,则将该头节点放到新数组时的索引位置等于其在旧数组时的索引位置,记为低位区链表lo开头-low; 不等于0时,则将该头节点放到新数组时的索引位置等于其在旧数组时的索引位置再加上旧数组长度

    41410

    HashMap JDK 1.8 深入学习笔录

    table数组中存放的下标,就是把元素的hash值和数组长度减1的值做一个与运算,即可求出该元素在数组中的下标,这条公式其实等价于hash%length,也就是对数组长度求模取余,只不过只有当数组长度为...这里有一个需要注意的点就是在JDK1.8 HashMap扩容阶段重新映射元素时不需要像1.7版本那样重新去一个个计算元素的hash值,而是通过hash & oldCap的值来判断,若为0则索引位置不变,...不为0则新索引=原索引+旧数组长度,为什么呢?...因此,我们在扩充HashMap的时候,不需要像JDK1.7的实现那样重新计算hash,只需要看看原来的hash值新增的那个bit是1还是0就好了,是0的话索引没变,是1的话索引变成“原索引+oldCap...那为什么1.8改成尾插法了呢?主要是因为头插法在多线程环境下可能会导致两个节点互相引用,形成死循环,由于此文主要讲解1.8版本,感兴趣的小伙伴可以去看看1.7版本的源码。

    9210

    面试再问 HashMap,求你把这篇文章发给他!

    注意:本文源码都是以JDK1.8版本讲解 数据结构 在 JDK1.8 中,HashMap 是由 数组+链表+红黑树构成(1.7版本是数组+链表) 当一个值中要存储到HashMap中的时候会根据Key的值来计算出他的...这里有一个需要注意的点就是在JDK1.8 HashMap扩容阶段重新映射元素时不需要像1.7版本那样重新去一个个计算元素的hash值,而是通过hash & oldCap的值来判断,若为0则索引位置不变,...不为0则新索引=原索引+旧数组长度,为什么呢?...因此,我们在扩充HashMap的时候,不需要像JDK1.7的实现那样重新计算hash,只需要看看原来的hash值新增的那个bit是1还是0就好了,是0的话索引没变,是1的话索引变成“原索引+oldCap...那为什么1.8改成尾插法了呢?主要是因为头插法在多线程环境下可能会导致两个节点互相引用,形成死循环,由于此文主要讲解1.8版本,感兴趣的小伙伴可以去看看1.7版本的源码。

    27510

    扫码

    添加站长 进交流群

    领取专属 10元无门槛券

    手把手带您无忧上云

    扫码加入开发者社群

    相关资讯

    热门标签

    活动推荐

      运营活动

      活动名称
      广告关闭
      领券