HashMap 是一个实现Java Collections Framework 的 Map 接口的类。 HashMap 最重要的特性是它具有恒定的检索和插入时间性能。决定 HashMap 性能的两个因素是:
- 初始容量
- 负载系数
在我们解释什么是 HashMap 的负载因子之前,有必要了解它的结构。
HashMap 的节点包含键值对,很像 Map 中的节点。 HashMap 有包含节点的桶,一个桶可能包含多个节点。 HashMap 的基本结构如下:
索引:是将key的hash值与数组大小减1后的按位AND运算得到的整数值。
Index = hashcode(key) & (ArraySize – 1)
其中 hashcode 是一个预定义的函数,它返回键的散列的整数值,ArraySize 是 HashMap 中的桶数。
Bucket :它是节点的 LinkedList 结构。
节点:它是HashMap的基本单元。它包含键值对和到下一个节点的链接。
声明 HashMap 对象的语法如下:
HashMap objectName = new HashMap(int initialCapacity, float loadFactor)
初始容量
初始容量本质上是 HashMap 中的桶数,默认情况下为2 4 = 16 。一个好的 HashMap 算法会将相同数量的元素分配到所有存储桶。
假设我们有 16 个元素,那么每个桶将有 1 个节点,任何元素的搜索都将通过 1 次查找实现。如果我们有 32 个元素,那么每个桶将有 2 个节点,任何元素的搜索都将通过 2 次查找实现。类似地,如果我们有 64 个元素,那么每个桶将有 4 个节点,任何元素的搜索都将通过 4 次查找来实现,依此类推。
正如您可以观察到的,当元素数量增加一倍时,查找增量增加 1,这对性能有好处。
但是当元素数量达到非常高的值时会发生什么,比如 10,000,在这种情况下,我们将需要 625 次查找。同样,如果元素数量为 10,00,000,我们将需要 62,500 次查找。如此大量的查找会降低 HashMap 的性能。这就是负载因子发挥作用的地方。
负载系数
Load Factor 是一个阈值,如果当前元素与初始容量的比值超过这个阈值,则容量增加,使得HashMap 的操作复杂度保持为O(1)。 O(1) 的操作复杂度的含义是指检索和插入操作需要恒定的时间。
HashMap 的默认加载因子是0.75f 。
我们如何决定何时增加容量?
让我们举个例子,由于默认的初始容量是 16,假设我们现在有 16 个桶。
We insert the first element, the current load factor will be 1/16 = 0.0625. Check is 0.0625 > 0.75 ? The answer is No, therefore we don’t increase the capacity.
Next we insert the second element, the current load factor will be 2/16 = 0.125. Check is 0.125 > 0.75 ? The answer is No, therefore we don’t increase the capacity.
Similarly, for 3rd element, load factor = 3/16 = 0.1875 is not greater than 0.75, No change in the capacity.
4th element, load factor = 4/16 = 0.25 is not greater than 0.75, No change in the capacity.
5th element, load factor = 5/16 = 0.3125 is not greater than 0.75, No change in the capacity.
6th element, load factor = 6/16 = 0.375 is not greater than 0.75, No change in the capacity.
7th element, load factor = 7/16 = 0.4375 is not greater than 0.75, No change in the capacity.
8th element, load factor = 8/16 = 0.5 is not greater than 0.75, No change in the capacity.
9th element, load factor = 9/16 = 0.5625 is not greater than 0.75, No change in the capacity.
10th element, load factor = 10/16 = 0.625 is not greater than 0.75, No change in the capacity.
11th element, load factor = 11/16 = 0.6875 is not greater than 0.75, No change in the capacity.
12th element, load factor = 12/16 = 0.75 is equal to 0.75, still No change in the capacity.
13th element, load factor = 13/16 = 0.8125 is greater than 0.75, at the insertion of the 13th element we double the capacity.
Now the capacity is 32.
以类似的方式,每次插入超过 0.75 的负载因子时,对于 get() {检索} 和 put() {插入} 操作的恒定时间性能,容量都会增加一倍。