解析源码,彻底弄懂HashMap(持续更新中)
为啥突然想着看HashMap源码了?
无意间看到有人说HashMap能考验Java程序员的基本功,之前我作为面试官帮公司招人的时候偶尔问起HashMap,大部分人回答基本都会用,且多数仅停留在put,get使用上面,实际上HashMap涉及的知识远远不止put和get那么简单。HashMap涉及线程、内存模型、Hash计算、链表结构、二进制运算等问题,可以说HashMap能考验一个Java程序员的技术功底。作为具备一定工作经验的技术人员,我们必须回头去恶补基础,凡是技术点都要努力去搞清楚是什么,为什么,怎么用。
HashMap基本概念及原理:
如果我们想要很快的查询一个数据,最好将其用数组存储,因为数组查询速度快,但是数组的长度不可以修改,所以它添加元素很麻烦,需要创建一个更大的数组,然后把老数组的元素按顺序拷贝到新数组中,而我们想要添加元素,最好使用链表去存储,因为链表是离散的,所以在添加或者删除的时候,只会修改局部的内容,也正是因为链表是离散的,它的位置在内存中不是一直固定的(指的是不连续),每次要查找下一个元素的时候,都需要读取其位置信息,所以链表的查询很慢。那有没有一种数据结构,它的查询很快,添加和删除速度也很快呢?答案是肯定的,结合数组和链表的优点,哈希表诞生了。
HashMap基于哈希表的Map接口实现,是以key-value的存储形式存在,即主要用来存放键值对。HashMap的实现不是同步的,这意味着它不是线程安全的。数组是HashMap的主体,链表则是为了解决hash冲突而存在的,所谓hash冲突就是两个对象调用hashCode()方法计算的hash值相同导致计算的数组索引也相同。
JDK1.8之后在解决Hash冲突时有了较大的变化,当链表长度大于边界值(默认为8)且当前数组长度大于64时,此时此索引位置上的所有数据改为使用红黑树存储。另外需要注意的是,当链表长度大于8但是数组长度小于64,此时也并不会将链表变成红黑树,而是选择扩容。这样做的目的是提高性能和较少搜索时间,具体可参照treeifyBin()方法。说了这么多,那HashMap的基本原理是怎样的呢?简单粗暴概括一下:
1、首先判断key是否为Null,如果为null,直接查找Enrty[0],如果不是Null,先计算Key的HashCode,得到Hash值,Hash值是一个int值。
2、根据Hash值,要找到对应的数组,所以对Entry[]的长度length取模(类似求余的算法,后面详细介绍),得到的就是Entry数组的index。
3、找到对应的数组就找到了所在的链表,然后按照链表的操作对Value进行插入、删除和查询操作。
HashMap底层数据结构及存储过程(以上纯属扯淡,下面重点来了):
JDK1.8之前HashMap底层由数组+链表实现
JDK1.8之后为了提高效率,底层由数组+链表+红黑树实现
在创建HashMap集合对象的时候,在JDK1.8之前是在构造方法中创建一个长度为16的Entry[] table来存储键值对,在JDK1.8之后不在构造方法中创建数组了,而是在第一次调用put()方法时创建数组Node[] table 用来存储键值对。


假设向哈希表中存储键值对key为zhangsan,value为28,根据zhangsan.hashCode()方法计算出hash值,然后结合数组长度采用取模的算法计算出zhangsan在Node数组中的索引值,如果计算出的索引没有值,则直接将28存储到数组中。那么,取模算法到底是怎样的呢?看下图。

红色框出来的代码告诉我们,采用的是按位与运算计算出索引值,其实就是我们熟知的取余法,但是为什么没有直接使用hash%length直接取余呢,是因为与运算效率更高,与运算规则:相同的二进制数位上都是1时结果为1,否则为0。在某种条件下hash%length等于n-1&hash,什么条件呢?那就是HashMap要求的数组长度length必须为2的n次幂,HashMap的构造函数允许我们自定义数组长度,但是它会检测然后自动帮我们把设置的长度往上转成最近的2的n次幂,比如我们初始化一个HashMap对象,设置数组长度为10,显然10不是2的某次幂,这时候会自动向上转成最近的2的某次幂,也就是16。
HashMap<String,String> hashMap = new HashMap<>(10);
解析源码,彻底弄懂HashMap(持续更新中)的更多相关文章
- Android源码编译常见错误(持续更新)
本文为个人工作中处理遇到的编译问题做个小结,后续遇到新的问题,持续更新. No such file or directory: 1. 检查路径是否有问题,文件是否存在,若文件存在且路径没问题 2. 检 ...
- IntelliJ IDEA 2019.2.1 破解教程, 最新激活码(激活到2089年8月,亲测有效,持续更新中...)
当前最新版本 IDEA 2019.2.1 本来笔者这边是有个正版激活码可以使用的,但是,2019.9月3号的时候,一些小伙伴反映这个注册码已经失效了,于是拿着自己的 IDEA, 赶快测试了一下,果不其 ...
- IDEA 2019.2破解激活教程(激活到2089年8月,亲测有效,持续更新中...)
本来笔者这边是有个正版激活码可以使用的,但是,2019.9月3号的时候,一些小伙伴反映这个注册码已经失效了,于是拿着自己的 IDEA, 赶快测试了一下,果不其然,已然是不能用了. 好在,笔者又找到了新 ...
- Flink 源码解析 —— 源码编译运行
更新一篇知识星球里面的源码分析文章,去年写的,周末自己录了个视频,大家看下效果好吗?如果好的话,后面补录发在知识星球里面的其他源码解析文章. 前言 之前自己本地 clone 了 Flink 的源码,编 ...
- EventBus源码解析 源码阅读记录
EventBus源码阅读记录 repo地址: greenrobot/EventBus EventBus的构造 双重加锁的单例. static volatile EventBus defaultInst ...
- 【JDK1.8】 Java小白的源码学习系列:HashMap
目录 Java小白的源码学习系列:HashMap 官方文档解读 基本数据结构 基本源码解读 基本成员变量 构造器 巧妙的tableSizeFor put方法 巧妙的hash方法 JDK1.8的putV ...
- Apache源码包在LINUX(CENTOS6.8)中的安装(出现问题及解决)
任务:在CENT6.8系统中安装Apache(版本为:httpd-2.4.41) 前提:由于源码包必须先编译后安装,所以必须先安装编译器:gcc 理论步骤: 1.检测gcc软件包,如果不存在则进行安装 ...
- 直播平台源码搭建教程:微信小程序中的直播如何去掉水印
直播平台源码搭建教程:微信小程序中的直播如何去掉水印 本文与大家分享一下直播平台源码搭建教程,如何去掉直播视频的水印 var services = require('../../lib/service ...
- fastadmin 后台管理框架使用技巧(持续更新中)
fastadmin 后台管理框架使用技巧(持续更新中) FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架,具体介绍,请查看文档,文档地址为:https://doc. ...
- 2020年腾讯实习生C++面试题&持续更新中(5)
2020年腾讯实习生C++面试题&持续更新中(5) 大家好呀,我是好好学习天天编程的天天~ 昨天一位小伙伴反馈已经拿到了腾讯offer,很是替小伙伴的激动~ 那今天还是持续给大家分享面经,希望 ...
随机推荐
- 将js进行到底:node学习6
开始真正的node web开发--express框架 为何说现在才是web开发的真正开始呢? 首先任何企业都不会用原生的http协议API去开发一个完整的网站,除非她们先开发一个框架出来,其次我们之前 ...
- HBase源码系列之HFile
本文讨论0.98版本的hbase里v2版本.其实对于HFile能有一个大体的较深入理解是在我去查看"到底是不是一条记录不能垮block"的时候突然意识到的. 首先说一个对HFile ...
- linux中nginx、mysql安装碰到的问题
服务器到期新买了一台服务器,记录一下重新安装基本环境碰到了一些问题 安装nginx 1. 启动失败 403 forbidden nginx 解决方案:(个人使用直接用了root账号,修改对应nginx ...
- Web 通信技术 ——跨文档信息传输(JavaScript)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.html * 作者:常轩 * 微信公众号:Worldh ...
- qt creator源码全方面分析(3)
目录 项目文件分析 qtcreator.pro 包含qtcreator.pri Qt版本判断 包含doc.pri 源码组织架构 指定dist文件列表 qbs配置 指定架构和平台 指定基础名 指定lin ...
- 第六周学习笔记,vc各类控件的输入输出
6w学习笔记 vc控件的输入输出 单选按钮 当单击 RadioButton 控件时,其 Checked 属性设置为 true,并且调用 Click 事件处理程序.当 Checked 属性的值更改时,将 ...
- python 临时文件
1. TemporaryFile 临时文件 TemporaryFile 不在硬盘上的生成真正文件,而是写在内存中 from tempfile import TemporaryFile # , Name ...
- VUE实现Studio管理后台(一):鼠标拖放改变窗口大小
近期改版RXEditor,把改版过程,用到的技术点,记录下来.昨天完成了静态页面的制作,制作过程并未详细记录,后期已经不愿再补了,有些遗憾.不过工作成果完整保留在github上,地址:https:// ...
- AOP面试知识整理,^_^-包括spring Aop
讲到java企业级开发框架,就不可避免的讲到 IOC,AOP,MCV 今天面试时被问到AOP,讲的很乱,这里整理笔记,包括AOP,spring-AOP的部分知识,错误的地方请小伙伴指出来. 谈谈你对A ...
- pip install mysqlclient报错(OSError: mysql_config not found)
报错截图 一般情况是系统没有安装libmysqld-dev 执行 sudo apt install libmysqld-dev完成安装后再 pip install mysqlclient就可以了(系统 ...