HashMap

1、HashMap

1.1、属性

table:Node类型的键值对。存储数据

entrySet:Set类型的参数

size:int类型,表示hashMap的大小

modCount:int类型,fail-fast标识

threshold:int类型,阈值,当hashMap的实际容量大于阈值时,要进行扩容。

loadFactor:float类型,加载因子

1.2、底层存储结构

实际存储数据的为Node

1.2.1、属性

hash:int类型,表示当前Node的key的hash值

key:K类型,表示当前键值对的key值

value:表示key对应的value值

next:Node,表示下一个键值对

1.2.2、构造函数

Node(int hash, K key, V value, Node next){

        this.hash = hash;

        this.key = key;

        this.value = value;

        this.next = next;

}

1.3、构造函数

1.3.1、HashMap()

初始化加载因子为默认的加载因子0.75。不初始化table,添加第一个数据时才初始化table

1.3.2、HashMap(int initialCapacity, int loadFactor)

自定义初始化容量和加载因子,一般不建议手动给加载因子。

1.3.3、HashMap(int initialCapacity)

自定义初始化容量,加载因子取默认的。

1.4、新增值

此处的hash值为key.hashCode^(key.hashCode >>> 16)

计算index的方式为hash&(capacity-1)

1.4.1、putVal(int hash,K key,V value,Boolean …)

      1.4.1.1、HashMap中没存值时:

    ①判断table是否为null或者table的length是否为0,

    ②为null或者0则调用resize()初始化table

    ③根据key值得hash值算出index,并判断下标为index的值是否为null

    ④为null则调用newNode()方法创建一个新的Node存入index处

    ⑤fail-fast标志modCount加1 ,table长度加1并与阈值threshold比较

    ⑥长度大于阈值,调用resize()方法进行扩容

   

      1.4.1.2、HashMap有值时:

    ①对比key值的hash与index下标处的Node的hash值,以及key值是否相等,若相等,将oldValue替换为newValue并返回oldValue

    ②判断key值hash对应的index处的Node是否为TreeNode(红黑树的节点),若为,调用TreeNode.putTreeVal()处理

    ③循环获取链表中最后一个节点p,并将需要新增的数据添加到p的next,即成为新的最后一个节点:同时判断链表长度是否超过8,若超过,则将调用treeifyBin()方法将链表结构转化为红黑树结构。

若当前table的存储size小于64时,不进行红黑树化,而进行扩容。

 

1.4.2、resize()

      1.4.2.1、初始化HashMap的table

        此时oldCap以及oldThr都是0,会直接设置newCap为16,threshold为16*0.75,即12。然后new一个大小为newCap的Node类型的数组返回

      1.4.2.2、HashMap进行扩容时

    ①设置好新的Capacity、threshold、

      1>当oldCapacity>0时

           若oldCap>=规定的Capacity时,将threshold设置为Integer.MAX_VALUE并返回旧的table,因为此时table扩容已达到上限

           否则将newCap扩容为oldCap的2倍,newThr变为oldThr的2倍

       2>当oldThr>0时,将newCap也设为一样大

    ②分情况重新将旧table中的数据存储到新的table中

       当前index只存了一个的、当前index存的是TreeNode类型的、存的是链表类型的

1.4.2.2.1、旧table中当前index只存了一个值

重新计算key值在新table中的index,将旧键值对赋值给新table的index处。

1.4.2.2.2、存储的是TreeNode类型

调用TreeNode.split方法。

1.4.2.2.3、存储的是链表类型的。

循环链表,计算新下标。

计算规则,将旧hash值与旧table长度做&运算,若为0,则新的index值与旧的index值相等;否则新的index为旧的index+oldCap。

你可能感兴趣的:(集合)