hashMap的底层实现

  hashMap 不用多说,你们确定都用过,今天我就hashMap的底层数据结构跟你们作一个分享。html

  hashMap 是基于哈希表的 Map 接口的实现,以key-value的形式存在。在HashMap中,key-value老是会当作一个总体来处理,系统会根据hash算法来来计算key-value的存储位置,咱们老是能够经过key快速地存、取value。HashMap实现了Map接口,继承AbstractMap。其中Map接口定义了键映射到值的规则,而AbstractMap类提供 Map 接口的骨干实现,以最大限度地减小实现此接口所需的工做。java

  hashMap中提供了3个构造方法,分别是:HashMap();HashMap(int initialCapacity);HashMap(int initialCapacity, float loadFactor)。这里面主要涉及到2个参数,分别是:initialCapacity(初始容量,默认为16)和loadFactor(加载因子,默认为0.75),举个例子你们就明白了。好比说我如今新建立一个hashMap,算法

Map map = new HashMap<String,Object>(16,0.75F);其中16表示该hashMap在初始化时的最大容量,或者说是哈希表中桶的数量,16*0.75=12表示该hashMap存储键值对的最大数量,
当map中继续put使键值对的数量大于12时,该map将会进行扩容的操做每次新建一个HashMap时,都会初始化一个table数组。table数组的元素为Entry节点。

 

 
static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        int hash;
}

 其中Entry为HashMap的内部类,它包含了键key、值value、下一个节点next,以及hash值,这是很是重要的,正是因为Entry才构成了table数组的项为链表(也就是java经过链地址法解决hashMap的hash冲突问题)。hash在进行put的时候,执行步骤以下: 首先判断key值是否为空,若为空,则调用putForNullKey方法(hashMap是支持key为null的),若不为空,则经过key来计算hash值,int hashCode = key.hashCode();再经过hashCode值计算该value存储在数组中的位置坐标index,计算方法为hashCode%size,size为该数组的长度;若是table数组在该位置处有元素,则经过比较是否存在相同的key,若存在则覆盖原来key的value,不然将该元素保存在链头(最早保存的元素放在链尾)。若table在该处没有元素,则直接保存。数组

hashMap在取出键值对的时候步骤大体和上面的差很少,只是在数组上该值存在于一个链表中的时候,要对链表进行遍历,经过equals()方法找到正确的value值。数据结构

补充说明一下:在java8.0之后,hashMap在存储结构上作了必定优化,主要是在链表的长度达到8的时候,会将链表转化成红黑树的方式存储,这是由于链表在长度比较长的时候进行遍历性能不是太好,而改用红黑树的数据结构能大大增长对数据的增删给查的效率,提升hashMap的性能。函数

HashMap的底层数组长度老是2的n次方,在构造函数中存在:initialCapacity<<= 1;这样作老是可以保证HashMap的底层数组长度为2的n次方。当length为2的n次方时,h&(length - 1)就至关于对length取模,并且速度比直接取模快得多,这是HashMap在速度上的一个优化。具体缘由能够参考博客:https://www.cnblogs.com/dassmeta/p/5338955.html性能

相关文章
相关标签/搜索