HashMap
1.HashMap的底层结构是什么?
● 在JDK1.7中,底层数据结构是数组+链表
● 在JDK1.8中,底层数据结构是数组+链表+红黑树
2.JDK1.8中什么情况下,链表会转变为红黑树?
● 当数组长度大于64且链表节点个数大于8时才会转变为红黑树,如果链表节点个数小于6则又会退化为链表
● 在链表转换为红黑树前面会进行判断,如果数组长度小于64,则会优先选择扩容。
3.为什么在解决 hash 冲突的时候,不直接用红黑树?而选择先用链表,再转红黑树?
● 因为红黑树需要进行左旋,右旋,变色这些操作来维持平衡,而单链表不需要,当元素小于8个的时候,此时查询操作,链表结构已经可以保证性能。当元素大于8个的时候,红黑树搜索事件负责度是0(logn),而链表是O(n),此时需要红黑树来加快查询速度,但是新增节点的效率变慢了
4.为什么用红黑树,不要二叉查找树
● 因为二叉查找树在极端条件下会变成线性结构,也就是链表,时间负责度没有改变
5.为什么链表转红黑树的阈值是8
● 因为泊松分布,作者在注释里面写了:按照泊松分布的计算公式计算出了桶中元素个数和概率的对照表,可以看到链表中元素个数为 8 时的概率已经非常小,再多的就更少了,所以原作者在选择链表元素个数时选择了 8,是根据概率统计而选择的
6.默认加载因子是多少?为什么是 0.75,不是 0.6 或者 0.8 ?
● 默认的loadFactor是0.75,0.75是对空间和时间效率的一个平衡选择。
7.为什么 hash 值要与length-1相与?
● 把 hash 值对数组长度取模运算,模运算的消耗很大,没有位运算快。
● 当 length 总是 2 的n次方时,h& (length-1) 运算等价于对length取模,也就是 h%length,但是 & 比 % 具有更高的效率。
8.hash冲突的解决方法
比较出名的有四种(1)开放定址法(2)链地址法(3)再哈希法(4)公共溢出区域法
9.我用LinkedList代替数组结构可以么?
可以但是没有必要,因为用数组效率最高! 在HashMap中,定位桶的位置是利用元素的key的哈希值对数组长度取模得到。此时,我们已得到桶的位置。显然数组的查找效率比LinkedList大。
10.我用ArrayList可以吗,ArrayList底层也是数组?
因为采用基本数组结构,扩容机制可以自己定义,HashMap中数组扩容刚好是2的次幂,在做取模运算的效率高。 而ArrayList的扩容机制是1.5倍扩容。
11.HashMap在什么条件下扩容
如果元素节点个数超过了loadfactorcurrent capacity,就要resize。加载因子数组大小。
12.说说String中hashcode的实现?
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
以31为权,每一位为字符的ASCII值进行运算,用自然溢出来等效取模。
哈希计算公式可以计为 s[0]31^(n-1) + s[1]31^(n-2) + … + s[n-1]
那为什么以31为质数呢?
主要是因为31是一个奇质数,所以31i=32i-i=(i<<5)-i,这种位移与减法结合的计算相比一般的运算快很多。
参考:https://zhuanlan.zhihu.com/p/76735726