无参构造
public HashMap(){//默认构造函数,赋值加载因子为默认的0.75this.loadFactor = DEFAULT_LOAD_FACTOR;}
这个是默认的构造函数,使用无参构造时,初始化加载因子。其他常量在put第一条数据的时候进行初始化。
有参构造
指定容量的构造
public HashMap(int initialCapacity){this(initialCapacity,DEFAULT_LOAD_FACTOR);}
指定容量的构造方法调用了下面的构造方法。传入了指定的初始化容量与默认的加载因子。
指定容量与加载因子的构造
public HashMap(int initialCapacity, float loadFactor){//对值进行边界处理if (initialCapacity < 0){throw new IllegalArgumentException("Illegal initial capacity:" + initialCapacity);}//初始化容量不能大于最大值if (initialCapacity > MAXIMUM_CAPACITY){initialCapacity = MAXIMUM_CAPACITY;}//加载因子不能为负if (initialCapacity <= 0 && Float.isNaN(loadFactor)){throw new IllegalArgumentException("Illegal load factor:" + loadFactor);}this.loadFactor = loadFactor;//根据期望值initialCapacity,返回2的n次方形式的哈希桶实际容量length,返回值一般会大于等于期望值this.threshold = tableSizeFor(initialCapacity);}
双参构造可以用来指定期望容量与加载因子,之所以叫期望容量是因为hashMap会对这个值进行处理,获取大于这个值且最接近的2的n次方的数。下面是tableSizeFor方法以及说明
private int tableSizeFor(int cap){int n = cap - 1;n |= n >>> 1;n |= n >>> 2;n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : n + 1);}
这里涉及二进制的运算,假设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的构造
public HashMap(Map<? extends K,? extends V> m ){this.loadFactor = DEFAULT_LOAD_FACTOR;putMapEntries(m,false);}
首先指定加载因子为默认加载因子,随后调用putMapEntries方法进行节点复制。这个方法在添加元素中会单独讲解。
