面试高频问题:HashMap实现原理

今天给同窗们讲讲一个面试常常遇到的高频问题,HashMap实现原理,但愿在金三银四的季节对同窗们有帮助。面试

HashMap结构图目录
 1、唠叨
 2、解析思路

 3、get方法
 4、put方法
 5、resize方法

 1、唠叨


认真阅读了下HashMap的实现方式,也参考了网上别人的一些解析,我的以为仍是有些东西想说。网上有的文章名字为HashMap源码解析,实际上就是给它里面的一些方法加上一些注释而已,有很多都是这样的。
我本身看源码的时候,发现不是别人不想解析,而是它的实现真的须要亲自研读,多理顺几遍才知道怎么回事。
我在这里解析的文字描述也较多,无论谁的解析,本身也都要看一下JDK源码的具体实现,咱们仅提供参考而已。数组

2、解析思路


源码不太方便看,先说明一下个人阅读思路。
1.把经常使用的几个方法拷贝到文本编辑器里面。
2.HashMap中不一样的时候会有不一样的流程,梳理方法中的逻辑流程。就像采用极端法,采用特殊的数据,而后查看方法执行语句。未执行的语句暂时不考虑。
3.注释源码...我以为HashMap的实现方式不够好,关键的几个方法里面包含的状况太多了,阅读起来是有难度的,而写程序的目的之一不就是让其余开发者阅读吗?一个方法内部作了太多的事情,违反了代码整洁的规则,一个函数作要尽可能少的事情。
解析
以前稍微介绍了一些HashMap的特性,HashMap初探。
(https://www.jianshu.com/p/be9ffb76db30)这里接着深刻。编辑器

3、get方法

先挑最简单的说函数

 

 

1 先从数组下标,找到对应的Node2. 
2 若是Node里的第一个节点命中,直接返回
3 若是有冲突,则经过key.equals(k)去查找对应的entry
4 若为树,则在树中经过key.equals(k)查找,O(logn);
5 若为链表,则在链表中经过key.equals(k)查找,O(n)。put方法这个中间涉及的逻辑多一些,方法须要分不一样的步骤看。spa

 


 

4、put方法


这个中间涉及的逻辑多一些,方法须要分不一样的步骤看。
思路:
1对key的hashCode()作hash,而后再计算index;
2若是没碰撞直接放到bucket里;
3若是碰撞了,以链表的形式存在buckets后;
4若是节点已经存在就替换old 5value(保证key的惟一性)
6若是碰撞致使链表过长(大于等于TREEIFY_THRESHOLD),就把链表转换成红黑树;
7若是Node的容量满了(超过load factor*current capacity),就要resize。3d



 

通常不发生碰撞的时候,相对简单,数据量较小的状况下。blog

 

 

我解释下关于碰撞冲的循环。
1.查看是否存在相同的key,存在相同的key跳出循环,覆盖key的value。
2.若是不存在相同的key,在链表末尾插入新的Node若是链表节点过长,转换为树。
3.若是链表节点过长,转换为树。索引

 

 

红黑树的部分,咱们下次单独解析ci

 5、resize方法


这个涉及的内容,有很多线须要捋一捋。首先看申明时候会resize()。它们都在调用put的时候执行的。开发

1.table == 的时候

 

 

2.键值映射的的数目大于临界值的时候。

 

 

6、resize具体方法


 

 

若是是第一次resize,咱们抽出来会执行到的语句。
1.初始化容量
2.初始化threshold,也就是初始化临界值,决定了table的键值对数目到何时会再次resize()


 

第二次及后续的resize执行流程

 


 

resize中对有碰撞的链表的操做写的颇有意思,再叙述一下。在从新分配索引的时候,有从新组建链表的操做。

举个比较夸张的例子,读者就明白了。
1.e.hash < 2,那么e.hash&oldCap就等于0,索引为小于以前hash表大小之内的索引。也就是当初的索引不变。
2.e.hash > 2的时候,e.hash&old不等于0,那么它的索引就为当前表的索引再加上新扩容的大小。


                案例图

这个图说的是,当hashmap的表大小为2扩充到4的时候,本来挂载在1位置的链表,从新分配以后的样子。

最后 篇幅有限,我这里仅仅介绍了get方法,put方法,resize方法的具体原理,文章就已经很是长了,不利于阅读。 下次再补充一下HashMap的hash方法原理,其他的相关注意事项。

相关文章
相关标签/搜索