hashMap内部有四个构造方法

无参构造

  1. public HashMap(){
  2. //默认构造函数,赋值加载因子为默认的0.75
  3. this.loadFactor = DEFAULT_LOAD_FACTOR;
  4. }

这个是默认的构造函数,使用无参构造时,初始化加载因子。其他常量在put第一条数据的时候进行初始化。

有参构造

指定容量的构造

  1. public HashMap(int initialCapacity){
  2. this(initialCapacity,DEFAULT_LOAD_FACTOR);
  3. }

指定容量的构造方法调用了下面的构造方法。传入了指定的初始化容量与默认的加载因子。

指定容量与加载因子的构造

  1. public HashMap(int initialCapacity, float loadFactor){
  2. //对值进行边界处理
  3. if (initialCapacity < 0){
  4. throw new IllegalArgumentException("Illegal initial capacity:" + initialCapacity);
  5. }
  6. //初始化容量不能大于最大值
  7. if (initialCapacity > MAXIMUM_CAPACITY){
  8. initialCapacity = MAXIMUM_CAPACITY;
  9. }
  10. //加载因子不能为负
  11. if (initialCapacity <= 0 && Float.isNaN(loadFactor)){
  12. throw new IllegalArgumentException("Illegal load factor:" + loadFactor);
  13. }
  14. this.loadFactor = loadFactor;
  15. //根据期望值initialCapacity,返回2的n次方形式的哈希桶实际容量length,返回值一般会大于等于期望值
  16. this.threshold = tableSizeFor(initialCapacity);
  17. }

双参构造可以用来指定期望容量与加载因子,之所以叫期望容量是因为hashMap会对这个值进行处理,获取大于这个值且最接近的2的n次方的数。下面是tableSizeFor方法以及说明

  1. private int tableSizeFor(int cap){
  2. int n = cap - 1;
  3. n |= n >>> 1;
  4. n |= n >>> 2;
  5. n |= n >>> 4;
  6. n |= n >>> 8;
  7. n |= n >>> 16;
  8. return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : n + 1);
  9. }

这里涉及二进制的运算,假设cap的值是100,则n的值是99,对应的二进制为:1100011
下面开始进行运算,>>>运算符的含义是无符号右移,忽略符号位左侧补0
n |= n >>> 1; n的值二进制表达为1110011
n |= n >>> 2; n的值二进制表达为1111111
n |= n >>> 4; n的值二进制表达为1111111
n |= n >>> 8; n的值二进制表达为1111111
n |= n >>> 16; n的值二进制表达为1111111
然后对其进行边界修正最后返回。
可以看到最终期望得到的值是1111111,转换为10进制是127,加1返回即2^7,为什么非要取2的n次方呢?这个在下面扩容的时候再讲解。

根据已有map生成hashMap的构造

  1. public HashMap(Map<? extends K,? extends V> m ){
  2. this.loadFactor = DEFAULT_LOAD_FACTOR;
  3. putMapEntries(m,false);
  4. }

首先指定加载因子为默认加载因子,随后调用putMapEntries方法进行节点复制。这个方法在添加元素中会单独讲解。