浅谈HashMap
1.负载因子
hashMap默认的负载因子是多少?为什么是这个值?
默认的负载因子是0.75,设置负载因子的目的是为了在hashMap容量满之前即使扩容(当前元素个数>= 负载因子*hashMap容量),也可以在new HashMap的时候指定负载因子大小。
hashMap在计算元素存放位置的时候不可避免的会出现hash冲突。解决冲突的方法就是往链表中追加,产生的冲突越多,链表的长度越长,就越影响HashMap的查询效率。
如何降低冲突:
1.足够完美的hash算法 (极限场景,每一次hash结果都是不同的)
2.足够多的桶(桶越多,越不容易计算在同一个桶中)。前者的优化空间已经很小了,所以就要保证足够多的桶的个数。
那为什么负载因子默认为0.75?
如果负载因子特别小,实际使用的空间远远小于已经new 出来的空间,太浪费内存。
如果负载因子特别大,等于1。举例,默认大小为16,负载因子1,等到添加第16个元素的时候才开始扩容,此时就剩一个桶。如果,负载因子是0.75,在添加第12个元素的时候已经进行了扩容,容量为16*2=32,添加到第16个元素的时候,还有17个空桶。很明显后者发生冲突的概率要小的多。
根据概率论计算取了一个中间值为0.75(经验值),还有一个原因就是,hashMap的容量永远为2的幂,0.75和2的幂相乘永远是一个整数。
总结:负载因子太大,冲突概率太高,导致hashMap中的链表长度变长,影响查询效率。负载因子太小,太浪费空间。所以取中间。
2.默认容量大小
hashMap默认容量大小是多少?为什么是这个值?
前面负载因子讲到了hashMap的容量为2的幂,参考源码:
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的幂。
那为啥偏偏是16,太小会怎样,太大又会怎样。
太小,会导致频繁扩容,hashMap扩容一次,所有元素要重新hash计算元素在桶中的位置,比较耗时。
太大,浪费空间。