众所周知HashMap添加数据的时候,是通过取模(取余)运算的,但为什么初始大小为16呢
先领大家看一段特性
令 x = 1<<n,即 x 为 2 的 n 次方,它具有以下性质假设x=16:
x : 00010000
x-1 : 00001111
令一个数 y 与 x-1 做与运算,可以去除 y 位级表示的第 4 位以上数:
y : 10110010
x-1 : 00001111
y&(x-1) : 00000010
这个性质和 y 对 x 取模效果是一样的:
y : 10110010
x : 00010000
y%x : 00000010
得出结论 y%x == y&(x-1)
位运算的代价比求模运算小的多,因此在进行这种计算时用位运算的话能带来更高的性能,
确定桶下标的最后一步是将 key 的 hash 值对桶个数取模:hash%capacity,如果能保证 capacity 为 2 的 n 次方,那么就可以将这个操作转换为位运算。
static int indexFor(int h, int length) {
return h & (length-1);
}
HashMap初始大小那什么要为16呢,HashMap的扩容为什么要是2倍?
2的N次方可以根据上诉性质采用位运算,所以为了提高性能初始大小为2的N次方,作为默认容量,太大和太小都不合适,所以16就作为一个比较合适的经验值被采用了
HashMap初始大小为2的N次方还有一个好处,再扩容时能大大减少计算的复杂度
对于一个key的hash值
hash(key的hash值) & oldCapacity = 1 桶位置为 桶位置和原来一致 + oldCapacity
hash(key的hash值) & oldCapacity = 0 桶位置和原来一致
假设oldCapacity = 16 key1 = 18 key2 = 33
oldCapacity : 00010000
newCapacity : 00100000
key1 hashCode: 00010010
key1 hashCode: 00100001
key1 & oldCapacity = 1 数组下标为 2(原桶位置)+ oldCapacity = 18
key2 & oldCapacity = 0 数组下标为 1 (原桶位置)= 1
加载因子什么是0.75?
提高空间利用率和 减少查询成本的折中,主要是泊松分布,0.75的话碰撞最小。
加载因子过高,例如为1,虽然减少了空间开销,提高了空间利用率,但同时也增加了查询时间成本;
加载因子过低,例如0.5,虽然可以减少查询时间成本,但是空间利用率很低,同时提高了rehash操作的次数。
在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少rehash操作次数,所以,一般在使用HashMap时建议根据预估值设置初始容量,减少扩容操作。
选择0.75作为默认的加载因子,完全是时间和空间成本上寻求的一种折衷选择
https://blog.csdn.net/diaopai5230/article/details/101211014
https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20%E5%AE%B9%E5%99%A8.md