HashMap之数组下标计算

  • 前提
    • loadFactor
    • capacity
    • threshold
  • put时,数组下标计算
    • hash函数
    • putVal函数
    • 核心计算
  • 扩容时,下标的重置计算

前提

HashMap是有数组+链表组成的,其中使用的算法有:hash(java8又使用了红黑树)

loadFactor

  • loadFactor是参与计算HashMap扩容的一个加载因子
  • new HashMap()会默认给loadFactor加载一个值0.75

capacity

  • capacity并非HashMap的属性,指的是HashMap数组的大小,即table.length

threshold

  • threshold是判断HashMap是否扩容的阈值
  • 官方注解上写的是 threshold = capacity * loadFactor

put时,数组下标计算

此处特别感谢zhangzhikai1同学的提醒

hash函数

static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

putVal函数

if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);
  • 汇总为:table下标i=(table.length- 1) & ((h = key.hashCode()) ^ (h >>> 16))
  • 当我们put的时候,会根据key获取对应的hash值,然后无符号右移16位(>>> 16),在与原本的hash值进行^计算,然后再与table.length-1进行&计算,最终得出需要放入的位置
  • 比如:key = “165156”,HashMap中table数组的大小为16,套入公式,那么我们就会计算出存放位置的下标为13
  • 通过这种方式计算出的值只能是0–15,不行你自己试试
  • 我们来看一下为什么

核心计算

  • (16-1)的二级制:0000 0000 0000 1111
  • &的计算方式是:同为1时为1,否则为0
  • 0000 0000 0000 1111的前12位都为0,那么和任何一个值进行&计算,最终得到的结果前12位只能为0
  • 0000 0000 0000 1111的后4位都是1,那么和任何一个值进行&计算,最终得到的结果还是原来的值
  • 最终的结果就是,把原有值的前12位归0,只保留后4位,最终转成十进制,结果集只能是0-15之间
  • 当前HashMap的table数组长度为16,下标值为0-15,膜拜我Doug Lea大神的神操作

扩容时,下标的重置计算

  • 在resize函数中,原HashMap的table数组扩容一倍,那么数组,以及链表中的对象,都需要重新分配位置
  • 那么在重新计算数组及链表中的位置时,情况分为三种
  • 第一种情况:数组有值,链表无值,这个时候只需要重新计算位置,放进去就OK了(e.hash & (newCap - 1))这个计算方式,就是上文数组下标计算,这里有个骚操作,可以结合第三种情况一起说
  • 第二种情况:数组有值,链表无值 ,但是红黑树有值,
  • 第三种情况:数组有值,链表有值,业务处理逻辑:循环列表判断每一个元素是否需要换位置,不需要的重新组合成链表,放入当前数组下标中,如果需要的,组成一个链表,放入指定的数组下标中
  • 第三种情况中判断元素是否需要换位置的依据是什么?if ((e.hash & oldCap) == 0) ,是这个判断,这个判断中e.hash指的是当前元素的hash值,oldCap指的是当前table数组的大小
  • 比如我们存放16个元素,而table数组的长度为4(原本默认为16,太大了,举例费劲),在假设16个元素的hash分别为0,1,2,3…一直到15,那么我们存放到table数组中的位置如下
下标 0 1 2 3
数组中的元素 e0(hash值为0) e1(hash值为1) e2(hash值为2) e3(hash值为3)
链表中的元素 e4(hash值为4) e5(hash值为5) e6 (hash值为6) e7 (hash值为70)
链表中的元素 e8(hash值为8) e9(hash值为9) e10(hash值为10) e11 (hash值为11)
链表中的元素 e12 (hash值为12) e13(hash值为13) e14(hash值为14) e15 (hash值为15)
  • 开始循环数组,获取到0下标,循环0下标中的元素(e0,e4,e8,e12)
  • e0,套入公式if((e.hash & oldCap) == 0) ------------ if((0&4)==0) ---------- true
  • e4,套入公式if((e.hash & oldCap) == 0) ------------ if((4&4)==0) ---------- false
  • e8,套入公式if((e.hash & oldCap) == 0) ------------ if((8&4)==0) ---------- true
  • e12,套入公式if((e.hash & oldCap) == 0) ------------ if((12&4)==0) ---------- false
  • e4,e12,是有需要移动的,那么移动的位置,我们也可以计算出来,是扩容后的下标为4的位置
  • 这既是Doug Lea的有一个神操作了,竟然都是需要移动到下标为4的地方,喊一波666。位置计算方式:数组下标计算
  • 而且基本上每个下标需要移动的数据n/2,取整,移动的位置刚好是当前位置i+扩容的差,如当前就是:i+4

HashMap之数组下标计算相关推荐

  1. HashMap如何计算数组下标

    讨论 代码环境为JDK1.8.0 211 HashMap如何计算数组下标 首先我们看看String的hashCode是如何计算的(出自JDK1.8.0 211 java.lang.String 145 ...

  2. 深入理解HashMap的存储以及计算过程,提高HashMap使用效率

    原文地址:http://www.iteye.com/topic/539465 /**      *@author annegu      *@date 2009-12-02      */ Hashm ...

  3. 编程之美2.15 二维数组最大子数组的和(数组下标从(1,1)开始)

          首先,我们看到这篇文章的题目,我们就会想到之前的那个题目 -- 连续子数组最大和问题.这个问题无疑就是把原问题扩展到二维的情况.       想起来这个问题也不是很难,我们可以求解一维矩阵 ...

  4. 【C 语言】字符串操作 ( 使用 数组下标 操作字符串 | 使用 char * 指针 操作字符串 )

    文章目录 一.使用 数组下标 或 指针 操作字符串 1.使用 数组下标 操作字符串 2.使用 char * 指针 操作字符串 二.代码示例 一.使用 数组下标 或 指针 操作字符串 1.使用 数组下标 ...

  5. hashmap有关问题与计算

    1.HashMap的存储方式是数组加链表,主干是一个Entry数组.Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对:当不同的key经过hash计算得出的in ...

  6. HashMap中数组初始化的秘密

    2019独角兽企业重金招聘Python工程师标准>>> 我们知道,在新建一个HashMap对象时,无论传的initialCapacity参数值为多少,最总HashMap中数组的长度始 ...

  7. 通过数组下标获取值都有哪些方法_通过面试题,让我们来了解Collection

    前言 欢迎关注微信公众号:Coder编程 获取最新原创技术文章和相关免费学习资料,随时随地学习技术知识! 本章主要介绍Collection集合相关知识,结合面试中会提到的相关问题进行知识点的梳理.希望 ...

  8. c++ string 无法通过下标访问_数组下标1你见过吗?

    作者:守望,Linux应用开发者,目前在公众号[编程珠玑] 分享Linux/C/C++/数据结构与算法/工具等原创技术文章和学习资源. 不知道你有没有见过-1作为数组下标的,我算是见到了.当然这一点在 ...

  9. 给定一个整数数组 nums和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标。

    问: /** 给定一个整数数组 nums和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标. 你可以假设每种输入只会对应一个答案.但是,数 ...

最新文章

  1. 人民大学提出听音识物AI框架,不用人工标注,嘈杂环境也能Hold住,还可迁移到物体检测...
  2. 准确率99.9%!如何用深度学习最快找出放倒的那张X光胸片(代码+数据)
  3. RedHat Enterprise Linux 5 安装GCC过程
  4. 6 有序集合ZSet(Sorted Set)
  5. Java技术分享:如何设计一个本地缓存?
  6. “疫”外爆发:没那么简单的视频会议
  7. MySQLdb的安装
  8. 前端服务器获取js文件偶尔慢_我所认识的前端性能优化
  9. 再见了古诺。 你好Drools工作台。
  10. html自动适应屏幕分辨率,css如何自适应屏幕大小?
  11. ubuntu apache服务器和gitweb服务器搭建
  12. ASP.NET页面请求处理
  13. C#开发:openfiledialog的使用
  14. Golang 大杀器之性能剖析 PProf
  15. EtherCAT总线运动控制学习笔记(RXXW_Dor)
  16. 关于金蝶K3系统(工业)供应链部分,使用前需要基本了解的一些信息
  17. MVC下压缩输入的HTML内容
  18. 如何启用计算机的远程服务,如何启用远程Windows命令行管理程序
  19. 2016·中国计算机辅助设计与计算机图形学大会
  20. Unity3d模型导入都需要注意哪些事项?

热门文章

  1. Android Device Unauthorized 的解决方案
  2. 03 k近邻法——课后习题答案
  3. Kanye West和软件开发有什么共同点……
  4. 电脑中的文件夹怎样转换成压缩包?干货分享!如何将电脑中的文件夹调整为压缩包?
  5. Unity3D 5.1烘培
  6. 随机变量及其分布函数
  7. 连续12年霸榜Gartner魔力象限,亚马逊云科技财报解析
  8. Linux共享文件夹的方法
  9. PHP输出菱形(一)
  10. 庄懂技术美术入门课笔记_L15_特效动态实现方式(UV流动UV扰动)