0.构造函数源码
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
第一个给的信息多就看第一个构造函数吧
public HashMap(int initialCapacity, float loadFactor) {
//一些校验
//如果传入容量小于零
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
//如果传入容量大于规定最大值就修改成最大值
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
//如果负载因子不合法抛出异常
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
//因为table的初始化长度必须是2的次方数,所以要先将不规则的initialCapcity通过 tableSizeFor 转化成2的次方数再乘以负载因子返回给threshold
this.threshold = tableSizeFor(initialCapacity);
}
前面的都是一些判断,判断传入参数是否合法
主要是最下面的 tableSizeFor函数,我们传入的cap可能是不规则的,通过tableSizeFor就可以返回最接近cap的2的次方数0.
为什么table.length一定要是2的次方数呢?
因为节点插入到数组的下标是
index = hashcode&table.length-1,HashMap为了减少碰撞,就要将数据分配均匀.hashcode&table.length-1能正常工作的前提就是table.length是2的次方数
为什么这样能均匀分布减少碰撞呢?2的n次方实际就是1后面n个0,2的n次方-1 实际就是n个1;
例如长度为9时候,3&(9-1)=0 2&(9-1)=0 ,都在0上,碰撞了;
例如长度为8时候,3&(8-1)=3 2&(8-1)=2 ,不同位置上,不碰撞;
1.tableSizeFor分析
static final 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;
}
传入给定的一个容量,通过一顿位运算操作返回成该数最近的较大的2的次方数
如何工作的?
比如传入的cap为10
cap == 10
n = 10-1=9 == 1001
1001 | 0100 ⇒ 1101
1101 | 0011 ⇒ 1111
1111 | 0000 ⇒ 1111
1111 ⇒ 15
return 15+1
最后返回了16