HashMap之数组下标计算
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之数组下标计算相关推荐
- HashMap如何计算数组下标
讨论 代码环境为JDK1.8.0 211 HashMap如何计算数组下标 首先我们看看String的hashCode是如何计算的(出自JDK1.8.0 211 java.lang.String 145 ...
- 深入理解HashMap的存储以及计算过程,提高HashMap使用效率
原文地址:http://www.iteye.com/topic/539465 /** *@author annegu *@date 2009-12-02 */ Hashm ...
- 编程之美2.15 二维数组最大子数组的和(数组下标从(1,1)开始)
首先,我们看到这篇文章的题目,我们就会想到之前的那个题目 -- 连续子数组最大和问题.这个问题无疑就是把原问题扩展到二维的情况. 想起来这个问题也不是很难,我们可以求解一维矩阵 ...
- 【C 语言】字符串操作 ( 使用 数组下标 操作字符串 | 使用 char * 指针 操作字符串 )
文章目录 一.使用 数组下标 或 指针 操作字符串 1.使用 数组下标 操作字符串 2.使用 char * 指针 操作字符串 二.代码示例 一.使用 数组下标 或 指针 操作字符串 1.使用 数组下标 ...
- hashmap有关问题与计算
1.HashMap的存储方式是数组加链表,主干是一个Entry数组.Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对:当不同的key经过hash计算得出的in ...
- HashMap中数组初始化的秘密
2019独角兽企业重金招聘Python工程师标准>>> 我们知道,在新建一个HashMap对象时,无论传的initialCapacity参数值为多少,最总HashMap中数组的长度始 ...
- 通过数组下标获取值都有哪些方法_通过面试题,让我们来了解Collection
前言 欢迎关注微信公众号:Coder编程 获取最新原创技术文章和相关免费学习资料,随时随地学习技术知识! 本章主要介绍Collection集合相关知识,结合面试中会提到的相关问题进行知识点的梳理.希望 ...
- c++ string 无法通过下标访问_数组下标1你见过吗?
作者:守望,Linux应用开发者,目前在公众号[编程珠玑] 分享Linux/C/C++/数据结构与算法/工具等原创技术文章和学习资源. 不知道你有没有见过-1作为数组下标的,我算是见到了.当然这一点在 ...
- 给定一个整数数组 nums和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标。
问: /** 给定一个整数数组 nums和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标. 你可以假设每种输入只会对应一个答案.但是,数 ...
最新文章
- 人民大学提出听音识物AI框架,不用人工标注,嘈杂环境也能Hold住,还可迁移到物体检测...
- 准确率99.9%!如何用深度学习最快找出放倒的那张X光胸片(代码+数据)
- RedHat Enterprise Linux 5 安装GCC过程
- 6 有序集合ZSet(Sorted Set)
- Java技术分享:如何设计一个本地缓存?
- “疫”外爆发:没那么简单的视频会议
- MySQLdb的安装
- 前端服务器获取js文件偶尔慢_我所认识的前端性能优化
- 再见了古诺。 你好Drools工作台。
- html自动适应屏幕分辨率,css如何自适应屏幕大小?
- ubuntu apache服务器和gitweb服务器搭建
- ASP.NET页面请求处理
- C#开发:openfiledialog的使用
- Golang 大杀器之性能剖析 PProf
- EtherCAT总线运动控制学习笔记(RXXW_Dor)
- 关于金蝶K3系统(工业)供应链部分,使用前需要基本了解的一些信息
- MVC下压缩输入的HTML内容
- 如何启用计算机的远程服务,如何启用远程Windows命令行管理程序
- 2016·中国计算机辅助设计与计算机图形学大会
- Unity3d模型导入都需要注意哪些事项?