HashMap实现原理一步一步分析(1-put方法源码整体过程)

今天给大家分享一下HashMap内部的实现原理, 这一块也是在面试过程当中基础部分被问得比较多的一部分。

想要搞清楚HashMap内部的实现原理,我们需要先对一些基本的概念有一些了解, 这些概念包括什么是hash、什么是hash表、什么是hashcode? 有了这些基本概念之后, 我们再去分析Hashmap,就相对来讲简单了一些。

什么是Hash

哈希(hash)简单理解就是将任意长度的输入通过散列算法转换成固定长度的输出,建立一种一一对应的关系.这个输出一般称之为散列码或哈希值。

常见hash算法

上面是文字概念如果你还不是太明白的话, 接下来列举一些常见的hash算法:

比如我们的MD5加密,假设你的密码为1234通过MD5加密后就变成了 81dc9bdb52d04dc20036dbd8313ed055这样一串加密。1234和81dc9bdb52d04dc20036dbd8313ed055就建立了一种对应的关系。 1234今后使用MD5加密得到的结果就是固定的81dc9bdb52d04dc20036dbd8313ed055值,得到的这个值我们称为hash值。

再比如我们的ASSIC码表,它也是一种hash算法,我们的一个字符'A'与数字65建立的这一种映射关系。我们的'A' 通过hash算法后,总是能找到固定数字 65,这个65我们就称它是Hash值。

Hash表

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。

如果我们想要存储多个字母, 存储多个值. 在Java当中可以使用数组来实现。如果我们直接把字母按照数组的角标进行存储的话, 按照如下方式进行存储。

image.png

假设此时我们想要获取到b的值 , 我们就须要先遍历,取出每一个元素判断是否等于b.这样效率就比较低。

现在就可以结合上面的上面讲的hash值来进行存储, 每一个字符都会有一个assic码的值, 我们可以获取该字母的assic值进行存储. 放到对象assic码值所在的角标位置,如下图:

image.png

通过这种方式存储,我们假设想要获取的内容,就只需要先算出a的assic码值97 在取的时候的时候直接arr[97] 即可直接取出对应位置的字码.无需再遍历数组进行比较。 这样的一个数组,根据关键码值(Key value)直接进行访问的数据结构,我们就称为是hash表。

HashCode

在上面存储字母a的时候,有同学可能会有疑问, 假设我的数组只有16个空间大小存储范围只有0到15. 字母a的assic码是97,直接进行存储的话, 不会是发生异常吗? 的确会是有这样的问题,所以我们在拿到hash值后, 并不是立即进行存储. 在这里我们先对获取的hash码值%16(16就是我们数组的长度),除以16取余数,这样就可以把范围固定在0-15之间,97%16得到结果1. 我们就把字母a存到1角标的位置arr[1]=a , 在取的时候我们使用同样的方式先获取a的assic码再%16 就可以直接获取到对应的值.如下图:


image.png

在这里面计算出来的数字1 也就是在数组当中存储的角标,我们就可以称它是a的hashcode码,hashcode码就是在hash表中有对应的位置.

HashCode的存在主要是为了查找的快捷性,HashCode是用来在散列存储结构中确定对象的存储地址的.

Object类中的hashCode方法

Java语言中,JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去,这样的话,下次做 Object的比较或者取这个对象的时候,它会依据对象的hashcode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。Object对象有个特殊的方法:hashcode() 此方法作用是到获取对应的hashcode码值。

HashMap内部数据结构:

有了上面的知识储备之后, 我们再来看HashMap的原理实现.hashmap内部的实现原理在JDK1.7与1.8当中有一个大的改变.

JDK1.7中使用的数据结构是:数组+链表

JDK1.8中使用的数据结构是:数组+链表+红黑树

接收下来我们先以JDK1.7当中的实现来去给大家讲,JDK1.7明白之后,1.8是在1.7的基本上加了一个红黑树。

HashMap实现原理

我们先来看一下hashMap的基本使用,如下图:

image

其中put方法中第一个参数为key(key必须是引用数据类型),第二个参数为value。 这一组key:value 我们称之为Entry,在hashmap中对应的是HashMap当中一个内部类,如下图:

image.png

我们每put一组key和value的时候, 就会给我们创建一个Entry对象. 把创建的entry对象放到数组当中去.在hashMap源码中我们可以看到如下的一些属性,其中就定义了数组的初始容量和空的数组。

image

我们的Entry对象会被放到table这个数组当中,如果下图.

image

在put一个元素时, 会先判断数组是否为空, 如果数组为空就去创建数组.

image

第26行位置帮我们初始化数组.从put方法的源码中我们可以看到, 内部的数组是懒加载的. 我们进入到该方法中查看

image

Entry对象往数组当中进行存放的时候,并不是直接按角标的形式进行存放. 采用hash表的形式进行存储。

在put元素时,entry对的的key必须一个引用数据类型. 引用数据类型在使用的时候可以调用hashcode()这个方法. 返回的是一串int类型的数字. 它这串数字当作是hash值进行存储到数组当中的对象位置. 这串数字比较大, 数组的存储空间大小只有16. 所以要对该数据进行取模 %16把结果限制在0-15之间(注:hashmap当中并不是直接取模,而是采用的位运算达到同样目的,这点后面介绍). 过程如下图:

image

在存储的过程当中可能会发生hash碰撞

什么是hash碰撞

所谓hash碰撞指的是经过hash算法之后, 计算出的hash码是同一个值,如下图:

image

在hashmap中为了解决这种情况,引入了链表,也就是我们在上面看Entry内部类声明的时候有一有个next的属性.如果产生了hash冲突,就会以链表头插发的形式来记录对应的数据.

举例: 假设现在角标9的位置被张三实体占用,是第一个放到角标9的位置

image

下一次再存放李四,假设李四经过hash之后,得到的位置也是9

image

会采用链表来解决hash冲突

image

后面如果再产生hash冲突,会遍历链表,查看有没有相同的entry对象,如果有,则进行更新操作,如果没有的话, 把该对象插入到链表头部. 如果没有产生hash冲突,直接存放到对应角标.

以下为put方法源码:

image

本篇内容就先介绍到这里, 关于hashmap的内容里面还有很多, 本篇内容主要先对hashmap内部的数组+链表有一个全局的认识. 里面还有很多问题我们还没有去分析. 比如:为什么数组的长度一定要为2幂次方, 添加元素时扩容的问题, 在1.7当中扩容转多数据时,多线程情况下为什么可能会产生cpu使用率100%的情况?. jdk1.8中加入了红黑树是什么意思?这些将会在下次给大家一个一个的进行分析.

原文链接:https://www.cnblogs.com/myxq666/p/14752171.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容