HashMap 的构造函数分析

2020-03-28  本文已影响0人  小李不秃

HashMap 系列文章

前言

上一节我们分析了 HashMap 的自定义常量的含义,这一节带大家分析一下 HashMap 的构造函数。


HashMap 构造函数

HashMap()

HashMap 无参构造函数,默认 table 初始化是 16,默认的加载因子是 0.75,这个在上一讲也讲过了,DEFAULT_INITIAL_CAPACITY 是 16,DEFAULT_LOAD_FACTOR 是 0.75。


HashMap()

HashMap(int initialCapacity)

HashMap(int initialCapacity),可以对容量进行设置,加载因子是 DEFAULT_LOAD_FACTOR ,调用的是下面的有参构造函数。


HashMap(int initialCapacity)

HashMap(int initialCapacity, float loadFactor)

HashMap(int initialCapacity, float loadFactor),可以指定容量和加载因子。容量不可以小于 0 ,也不可以无限大。加载因子也不能是 0 ,也不能比 0 小。并且不能是 NaN (详见)。
然后给 loadFactor 进行赋值,并且给对阈值 threshold 进行设置。我们可以看一下 tabSizeFor 方法。

HashMap(int initialCapacity, float loadFactor)

对于给定的容量进行计算,返回 2 的 n 次方。那这块的计算规则,我给你们讲解一下。

tabSizeFor
首先我们看一下运算符的优先级 (详见)

我们知道先进行位移预算,再进行与运算,然后再给 n 进行赋值。

这块的意思是什么,就是以你的最高位为基准,然后让后面的位置都是1。

那我举个例子,你就明白了,

比如 cap 是 17,那么 n 就是 17-1 = 16

16 对应的二进制是 10000。

那咱们一步一步的算:

首先

n |= n>>>1

n >>> 1,标识 n 右移 1 位,那么 n = 01000

10000 | 01000 = 11000

n = 11000

第二步

n >>> 2, 标识 n 右移 2 位,那么 n = 00110

11000|00110 = 11110

n = 11110

第三步

得到 n = 11111

最终就得到 n = 11111 也就是换算成十进制也就是 31,那返回结果就是 31+1 = 32

所以不管你输入的是多少,比如十进制 100 换算成二进制就是 1100100 那么得到的结果就是 1111111 就是 127,那返回结果就是 128。

而为什么偏要是 2 的 n 次方呢?这里提前透露一下,当进行 put 的时候,会计算 hash 值,然后进行 hash 值得优化,并且把优化后的 hash 值和 size-1 进行一个与(&)运算。这个会在后续进行更详细的讲解。

HashMap(Map<? extends K, ? extends V> m)

HashMap(Map map) 创建一个新的 HashMap ,加载因子是 DEFAULT_LOAD_FACTOR 。然后通过 putMapEnries 将 map 的值存储到新的 HashMap 中。

HashMap(Map<? extends K, ? extends V> m)

putMapEntries 方法主要分为三步

  1. 如果 HashMap 没有创建,给阈值设值。
  2. 如果 HashMap 不为 null,根据阈值判断是否需要扩容。
  3. 通过 entrySet() 获取 map 的所有键值,通过循环,用 getKey() 和 getValue() 获取键值,然后 put 到新的 HashMap 中。


    putMapEntries 方法

总结

HashMap 有四个构造函数,分别是:

通过构造函数可以设置容量和加载因子,容量必须大于 0 ,最大不能超过 MAXIMUM_CAPACITY,而且通过 tabSizeFor(int cap) 方法返回 2 的 n 次方,并且赋值给 threshold。threshold 是 HashMap 的阈值,在 resize() 方法初始化 table 的时候,threshold 是初始化 table 的容量大小。这个 resize() 方法在后面会详细讲解。所以为了减少扩容和 hash 冲突,我们可以在创建 HashMap 的时候提前控制容量和加载因子的大小,来提升系统的性能。

上一篇下一篇

猜你喜欢

热点阅读