javahashmap怎么用(Java集合HashMap源码学习)(1)

HashMap是我们常见的Map接口实现,用于存储键值对。HashMap是线程异步的,并且存储数据是无序的,所以我们可以通过Map m = Collections.synchronizedMap(new HashMap(…))来创建线程同步的Map对象。HashMap的性能由两个参数来影响,初始化大小和扩容因子,初始化大小就是用来存储HashMap值的hash table的大小,扩容因子是用来实现HashMap的自动扩容的,默认是0.75。

HashMap的定义

javahashmap怎么用(Java集合HashMap源码学习)(2)

通过上面的源码,我们来分析下HashMap的结构。

大小

HashMap中定义了两个大小的常量。最小大小是4,最大的大小是1<<30。HashMap满的时候也会自动进行扩容,扩容大小因子是0.75。

存储

HashMap中的值存储在table和entryForNullKey中。table是类型HashMapEntry< K, V>的数组,entryForNullKey是HashMapEntry< K, V>类型。table中用于存储我们的值,entryForNullKey用于存储null值。

扩容

源码中介绍的扩容因子是DEFAULT_LOAD_FACTOR=0.75,那么什么时候触发扩容操作呢?这里就需要注意到threshold门限。当HashMap的大小超过阈值的时候,table会重新计算hashCode。threshold大小等于0.75*capacity。

构造函数

javahashmap怎么用(Java集合HashMap源码学习)(3)

该构造函数中,传入指定大小的capacity。如果大小小于0,则抛出IllegalArgumentException异常。如果大小=0,则构建一个EMPTY_TABLE,并将该值赋值给table,同时初始化threshold值=-1。接着就是判断capacity的大小,然后通过makeTable初始化一个table和threshold的值。

在上面多次出现HashMapEntry类。我们来看下:

javahashmap怎么用(Java集合HashMap源码学习)(4)

它的定义就类似我们数据库中的Node节点,用于存储当前节点的key和value信息。同时存储next节点的信息。

HashMap添加数据

hashMap通过put方法添加值。

javahashmap怎么用(Java集合HashMap源码学习)(5)

首先我们看到如果key=null值,则将key插入到entryForNullKey中。反之则通过secondaryHash方法二次计算key的hashcode,然后将hashcode与table的大小进行&运算,计算出该key、value在数组中应该存储的index。接着就是遍历table,判断当前index位置上的HashMapEntry值是是否有值,这里的判断条件是该位置上元素的hashCode和key是否跟插入元素的相同。如果相同,替换原来的元素。如果当前位置上元素不与此值相同,则将元素构建插入。ps:其实这里的本质就是哈希表中处理碰撞方法的一种,叫链地址法。

HashMap获取元素

javahashmap怎么用(Java集合HashMap源码学习)(6)

首先根据key的hashCode计算出在table中的index。当找到与指定key相同的位置返回该位置的value,或者当找到hash值与key的相同并且key.dquals与之相等,则进行数据反馈。

通过对上面方法的了解,我们知道针对在Map中添加元素,需要进行HashCode和equals方法的判断。

因为Map这个类没有继承Iterable接口所以不能直接通过map.iterator来遍历(list,set就是实现了这个接口,所以可以直接这样遍历),所以就只能先转化为set类型,用entrySet()方法,其中set中的每一个元素值就是map中的一个键值对,也就是Map.Entry了,然后就可以遍历了。

基本上 就是遍历map的时候才用得着它吧。

javahashmap怎么用(Java集合HashMap源码学习)(7)

,