HashMap实现原理理解

    很多童鞋看过很多关于HashMap的文章, 但是还是对其一知半解,感觉灰常复杂,难以理解与掌握,即便看了源码,也是云里雾里。包括本人也是如此。

    好,闲话少说,进入正题。

    HashMap大家经常都有用到,对于put、get、Entry三个东东都不会陌生,大家都知道HashMap允许null键null值,不允许重复的Key,并且HashMap能够扩容,在线程安全方面,HashMap不是同步的。但是大家知道这是为什么吗?回答了这些个问题,就相当于回答了HashMap的实现原理。

    下面我将从HashMap的数据结构上来回答这个问题。

    在讲下面的内容之前,先要明白HashMap的几个重要属性:初始容量、因子、Entry<K,y>[]。Entry大家可能都知道,但是初始容量和因子可能就不是很清楚了。我们平时构造一个HashMap对象的时候,一般都是使用HashMap()构造器,其实HashMap还有另外三个构造器,其中两个构造器的参数中就包含了初始容量和因子。如图:

    

那么,初始容量与因子是什么意思,起到什么作用呢?

初始容量的意思就是HashMap的初始大小;因子的作用是,当当前的HashMap容量使用超过75%时,HashMap将触发容量扩容,扩容之后的容量是原来的两倍。

HashMap的扩容是怎么回事呢?

因为HashMap的键值对其实是存储在Entry<K,V>[]数组中的。数组本身不会自动扩容,是因为HashMap去实现了这个功能,对于外部使用者的我们,我们感知不到其内部的变化,感觉上就好像HashMap存多少键值对都可以,真的灰常神奇,其实并没有那么腻害,它只不过是把键值对存储在内部类Entry<K,V>数组中,HashMap的扩容的过程只不过是创建一个容量是原来Entry数组容量两倍的新的Entry<K,V>[]数组,并将原来的Entry数组中的元素拷贝的新的Entry数组中,老的Entry数组丢弃,这就完成了扩容,其实一点也不神秘。

HashMap允许null键null值,不允许重复的Key,为什么?

put方法的实现,就说明了这个问题。 

简单的说,当put(K,V)的时候,检查K是不是null,如果是null,就存到null键值对中;如果不是null,就检查K在HashMap中是否存在,如果存在就覆盖掉V值,否则就新增一个键值对。

深一点来说,如何判断一个K在HashMap中是否存在呢?put的时候, 我们首先是hsah(K)获取K的hash值,然后根据hash值和Entry数组的长度去获取hash值在Entry数组中的位置,然后,从这个位置开始遍历Entry数组,找到一个不等于null的元素e,如果hash == e.hash && (K == e.key || K.equals(e.k)),则说明这个K在HashMap中存在,否则就addEntry。 这就是为什么HashMap允许null键null值,以及不允许重复Key的原因。        

还有好多没有写,以后再补充吧.............................


阅读更多

没有更多推荐了,返回首页