HashMap是使用数组+链表的数据结构进行数据的存储,后来演变到jdk8之后,为了提高插入和查询效率,在插入的数据超过某个阀值之后,会将数组+链表的结构转化为数组+红黑树的数据结构。
1.初始化
1.1初始化
当我们执行下面的代码时
java"> HashMap<String,Integer> map = new HashMap<>();
我们从底层代码发现是对其内部的一个loadFactor属性进行了初始化,默认值为0.75,那么我们为什么要初始化loadFactor参数呢?这个loadFactor参数具体是干什么的呢?
HashMap是用的一个数组+链表的形式进行数据的存储,那么这个数组的长度是如何决定的呢?我们用什么来判断要对数组进行扩容/缩减呢?这个判断依据就是根据loadFactor来决定的。当插入数据的个数/数组的长度>=loadFactor时,我们就要对数组的长度进行扩展。因为当插入的数据越来越大的时候,在数组长度不变的情况下hash冲突会越来越严重,数组节点下的数据就会越来越多,进而导致查询效率越来越差。
在扩展数组的时候,数组的长度都是2^n个,在初始化的时候,数组长度是2^4=16,每一次扩展,都增加一倍。
1.2插入第一条数据
java"> map.put("apple",2);
当我们执行这条操作的时候
第一步:先计算字符串"apple"的hash值,作为判断插入数据在哪个节点的依据。
第二步:初始化数组表table,第一次初始化的时候,数组表table的长度是2^4=16
第三步:用"apple"的hash值和数组table的长度(n-1)做且运算,判断当前数据应该插在数组的哪个位置(注:做且运算时确保数据插入位置是在[0,n-1]之间,保证数组不会越界)
java">if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);
第四步:size字段+1,并判断是否超阀值threshold,则进行数组table扩展,且以后每插入一条数据,都会进行阀值判断。(注:threshold = 当前数组table的长度 *loadFactor)
java">if (++size > threshold)resize();