讨论 代码环境为JDK1.8.0 211

HashMap如何计算数组下标

首先我们看看String的hashCode是如何计算的(出自JDK1.8.0 211 java.lang.String 1452行—1476行)

/*** Returns a hash code for this string. The hash code for a* {@code String} object is computed as* <blockquote><pre>* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]* </pre></blockquote>* using {@code int} arithmetic, where {@code s[i]} is the* <i>i</i>th character of the string, {@code n} is the length of* the string, and {@code ^} indicates exponentiation.* (The hash value of the empty string is zero.)** @return  a hash code value for this object.*/public int hashCode() {int h = hash;if (h == 0 && value.length > 0) {char val[] = value;for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h;}return h;}

String类重写了hashCode()函数,计算字符串的hashCode的公式为:
s[0]∗31n−1+s[1]∗31n−2+...+s[n−1]s[0]*31^{n-1}+s[1]*31^{n-2}+...+s[n-1] s[0]∗31n−1+s[1]∗31n−2+...+s[n−1]
我们来举个例子:
经过debug我们得知三个字符串的hashCode()返回值,我们来通过计算公式模拟一下:
字符串“a”,长度n=1,字符‘a’=97,代入公式得:
s[0]∗31n−1+s[1]∗31n−2+...+s[n−1]=97∗311−1=97s[0]*31^{n-1}+s[1]*31^{n-2}+...+s[n-1]=97*31^{1-1}=97 s[0]∗31n−1+s[1]∗31n−2+...+s[n−1]=97∗311−1=97
字符串“ab”,长度n=2,字符‘a’=97,‘b’=98,代入公式得:
s[0]∗31n−1+s[1]∗31n−2+...+s[n−1]=97∗312−1+98∗311−1=3105s[0]*31^{n-1}+s[1]*31^{n-2}+...+s[n-1]=97*31^{2-1}+98*31^{1-1}=3105 s[0]∗31n−1+s[1]∗31n−2+...+s[n−1]=97∗312−1+98∗311−1=3105
好了知道了如何计算String的hashCode,再来看看HashMap的hash()函数是如何利用hashCode的:

如果key对象为null的话,就返回一个0,当然String对象为null的话,强行计算hashCode()是会抛出空指针异常的。如果key对象不是为null,那么获取key的hashCode,然后与右移位16位后的hashCode进行异或操作(关于异或操作,总结:不同,结果为1,相同,结果为0),异或的结果就位hash()函数返回值。我们以String的hashCode()为例,图解计算一次hash()返回值:

通过debug,我们知道“my name is suser!”的hashCode返回值为:244633208,然后通过进制转换为二进制,方便计算

我们图解一下计算过程:

得到hash(key)=244629740后,下一步计算数组下标,我们看源码中第630行:

tab[i = (n - 1) & hash]

在JDK1.8中,HashMap底层为数组+链表或红黑树
i是什么?i就是数组下标;
n是什么?n是数组长度,默认为16
hash就是hash(key)函数的返回值,244629740为例,这里要得出下标,需要进行一次&(与运算)(同为1,则1,不然则为0)
这里,假设HashMap刚刚创建,也没有经过扩容操作,数组长度这时为默认的16,来算算下标:

最终计算得下标值为12。
下面,通过debug结果,给出证据,证明其下标值确定为12:

625行debug信息显示hash(key)返回值,key值等关键信息
630行debug信息显示此时HashMap数组长度为默认16,还未经过扩容操作
631行debug信息显示i的值为12,与我推想的结果一致

总结一下: HashMap中数组下标值的计算过程,大致分为如下几步:获取key.hashCode(),然后将hashCode高16位和低16位异或(^)操作,然后与当前数组长度-1结果进行与(&)操作,最终结果就是数组的下标值。
至于由于当前结点(键值对)的加入,导致当前HashMap中容量超过了阈值而扩容2倍,扩容后导致每个结点重新计算下标值(称为新下标值),新下标值只有两种可能:一、key的hash()返回值新加入与(&)操作计算的一位为0,则下标值与原下标值相同。二、key的hash()返回值新加入与(&)操作计算的一位为1,则计算出来的下标值=原下标值+原数组长度。
如果key对象为Integer,他的hashCode()直接返回的value。

HashMap如何计算数组下标相关推荐

  1. HashMap之数组下标计算

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

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

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

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

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

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

    题目链接:https://leetcode-cn.com/problems/two-sum/solution/liang-shu-zhi-he-by-leetcode-2/ 给定一个整数数组 nums ...

  5. hashmap和数组哪个速度快

    Chasel_s  最近去面试遇到了面试官问的很多问题,很多东西可能之后真正被人问过之后才会发现自己学了假的知识, 答对的就不说了,今天栽在java的数据结构上了,面试官今天问了我一个问题,数组和ha ...

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

    标题:java,给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 一.示例 二.题解 方法一,暴力法:使用双重for循环,每 ...

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

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

  8. 第1题 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标

    package com.leetcode; import java.util.ArrayList; import java.util.HashMap; import java.util.List; i ...

  9. byte[]数组下标的最大值

    原以为int.MaxValue就是所有数组下标的最大值,编译也能通过,结果运行时发现报错:内存溢出. 经过测试发现,原来在不同的系统/不同的配置上,这个值都不太一样,我笔记本经过测试 byte[] b ...

最新文章

  1. typora新增主题,typora将主题导入本地
  2. 图解计算机中数据的表示形式
  3. java设计模式简述
  4. hibernate中持久化对象的生命周期(三态:自由态,持久态,游离态 之间的转换)...
  5. python中的数据类型有哪些是可阅读,Python中典型的数据类型中哪个只能阅读不能修改...
  6. nagios 使用mysql_Nagios监控MySQL
  7. (2021年)IT技术分享社区个人文章汇总(数据库篇)
  8. php html 停止工作,换行符php和html无法正常工作
  9. [No0000FD]C# 正则表达式
  10. ie9 jscript7 内存不足 页面无响应
  11. 本人见过的最有用的日志!不来转藏肯定后悔
  12. 一对一语音视频直播双端原生+php后台源码 社交交友APP匹配语音视频聊天即时通信源码
  13. android局域网怎么传文件,两手机同一局域网怎么传文件
  14. 如何拆分PDF成单页?这三个方法分享给你
  15. webview跳转第三方小程序
  16. centOS 8 报错:Failed to set locale, defaulting to C.UTF-8
  17. HPUX 11iV3 LVM新变化
  18. 阿里云大数据平台的实操:ODPS的SQL语句
  19. java毕业生设计在线辅导答疑系统计算机源码+系统+mysql+调试部署+lw
  20. MongoDB中不溜教程(1)简介与命令

热门文章

  1. 12306火车票订票项目源码
  2. php中抓取https页面,php抓取https url网页内容方法
  3. IDEA开发工具的安装及使用
  4. Flink的两阶段提交
  5. 【C++】【哈希表】【哈希函数】实现自己的哈希表,解决哈希冲突;动态哈希表;
  6. TCP UDP socket http webSocket 之间的关系
  7. List 根据下标删除元素
  8. 湖南文理计算机应用,三尺讲台迎冬夏 两寸笔头耕未来 ----记湖南文理学院计算机科学与技术学院娄小平博士...
  9. AES加密原理及简单逆向解题思路 - 从0开始的repwn 02
  10. Snapshot Diagram画法小结