为啥突然想着看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(持续更新中)的更多相关文章

  1. Android源码编译常见错误(持续更新)

    本文为个人工作中处理遇到的编译问题做个小结,后续遇到新的问题,持续更新. No such file or directory: 1. 检查路径是否有问题,文件是否存在,若文件存在且路径没问题 2. 检 ...

  2. IntelliJ IDEA 2019.2.1 破解教程, 最新激活码(激活到2089年8月,亲测有效,持续更新中...)

    当前最新版本 IDEA 2019.2.1 本来笔者这边是有个正版激活码可以使用的,但是,2019.9月3号的时候,一些小伙伴反映这个注册码已经失效了,于是拿着自己的 IDEA, 赶快测试了一下,果不其 ...

  3. IDEA 2019.2破解激活教程(激活到2089年8月,亲测有效,持续更新中...)

    本来笔者这边是有个正版激活码可以使用的,但是,2019.9月3号的时候,一些小伙伴反映这个注册码已经失效了,于是拿着自己的 IDEA, 赶快测试了一下,果不其然,已然是不能用了. 好在,笔者又找到了新 ...

  4. Flink 源码解析 —— 源码编译运行

    更新一篇知识星球里面的源码分析文章,去年写的,周末自己录了个视频,大家看下效果好吗?如果好的话,后面补录发在知识星球里面的其他源码解析文章. 前言 之前自己本地 clone 了 Flink 的源码,编 ...

  5. EventBus源码解析 源码阅读记录

    EventBus源码阅读记录 repo地址: greenrobot/EventBus EventBus的构造 双重加锁的单例. static volatile EventBus defaultInst ...

  6. 【JDK1.8】 Java小白的源码学习系列:HashMap

    目录 Java小白的源码学习系列:HashMap 官方文档解读 基本数据结构 基本源码解读 基本成员变量 构造器 巧妙的tableSizeFor put方法 巧妙的hash方法 JDK1.8的putV ...

  7. Apache源码包在LINUX(CENTOS6.8)中的安装(出现问题及解决)

    任务:在CENT6.8系统中安装Apache(版本为:httpd-2.4.41) 前提:由于源码包必须先编译后安装,所以必须先安装编译器:gcc 理论步骤: 1.检测gcc软件包,如果不存在则进行安装 ...

  8. 直播平台源码搭建教程:微信小程序中的直播如何去掉水印

    直播平台源码搭建教程:微信小程序中的直播如何去掉水印 本文与大家分享一下直播平台源码搭建教程,如何去掉直播视频的水印 var services = require('../../lib/service ...

  9. fastadmin 后台管理框架使用技巧(持续更新中)

    fastadmin 后台管理框架使用技巧(持续更新中) FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架,具体介绍,请查看文档,文档地址为:https://doc. ...

  10. 2020年腾讯实习生C++面试题&持续更新中(5)

    2020年腾讯实习生C++面试题&持续更新中(5) 大家好呀,我是好好学习天天编程的天天~ 昨天一位小伙伴反馈已经拿到了腾讯offer,很是替小伙伴的激动~ 那今天还是持续给大家分享面经,希望 ...

随机推荐

  1. 将js进行到底:node学习6

    开始真正的node web开发--express框架 为何说现在才是web开发的真正开始呢? 首先任何企业都不会用原生的http协议API去开发一个完整的网站,除非她们先开发一个框架出来,其次我们之前 ...

  2. HBase源码系列之HFile

    本文讨论0.98版本的hbase里v2版本.其实对于HFile能有一个大体的较深入理解是在我去查看"到底是不是一条记录不能垮block"的时候突然意识到的. 首先说一个对HFile ...

  3. linux中nginx、mysql安装碰到的问题

    服务器到期新买了一台服务器,记录一下重新安装基本环境碰到了一些问题 安装nginx 1. 启动失败 403 forbidden nginx 解决方案:(个人使用直接用了root账号,修改对应nginx ...

  4. Web 通信技术 ——跨文档信息传输(JavaScript)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.html * 作者:常轩 * 微信公众号:Worldh ...

  5. qt creator源码全方面分析(3)

    目录 项目文件分析 qtcreator.pro 包含qtcreator.pri Qt版本判断 包含doc.pri 源码组织架构 指定dist文件列表 qbs配置 指定架构和平台 指定基础名 指定lin ...

  6. 第六周学习笔记,vc各类控件的输入输出

    6w学习笔记 vc控件的输入输出 单选按钮 当单击 RadioButton 控件时,其 Checked 属性设置为 true,并且调用 Click 事件处理程序.当 Checked 属性的值更改时,将 ...

  7. python 临时文件

    1. TemporaryFile 临时文件 TemporaryFile 不在硬盘上的生成真正文件,而是写在内存中 from tempfile import TemporaryFile # , Name ...

  8. VUE实现Studio管理后台(一):鼠标拖放改变窗口大小

    近期改版RXEditor,把改版过程,用到的技术点,记录下来.昨天完成了静态页面的制作,制作过程并未详细记录,后期已经不愿再补了,有些遗憾.不过工作成果完整保留在github上,地址:https:// ...

  9. AOP面试知识整理,^_^-包括spring Aop

    讲到java企业级开发框架,就不可避免的讲到 IOC,AOP,MCV 今天面试时被问到AOP,讲的很乱,这里整理笔记,包括AOP,spring-AOP的部分知识,错误的地方请小伙伴指出来. 谈谈你对A ...

  10. pip install mysqlclient报错(OSError: mysql_config not found)

    报错截图 一般情况是系统没有安装libmysqld-dev 执行 sudo apt install libmysqld-dev完成安装后再 pip install mysqlclient就可以了(系统 ...