前言
阿巴阿巴约了面试,面试官问她对HashMap的了解。
<Center>回去等告诉</Center>
面试官: HashMap理解吗?来谈谈你对这块的了解。
阿巴阿巴: 嗯嗯好,先从HashMap的构造开始吧,HashMap是一种散列表,由数组+链表+红黑树组成,初始默认的容量是16,负载因子是0.75,当链表上的元素大于8时链表进行红黑树化,当红黑树上元素缩小到6时,红黑树会进化为链表。
阿巴阿巴: HashMap次要有2个重要办法,put/get,put办法就是将元素无序的退出到HashMap中,也就是无奈保障元素的插入程序,get办法就是获取HashMap中的元素。
阿巴阿巴: 此外还有一个扩容的办法,扩容阈值为以后容量 * 负载因子,每次扩容后的容量都是之前容量的2倍。
面试官: 很好,还有吗?
阿巴阿巴: 额......如同容量必须是2的次幂,嗯....额.....
面试官: 好的,明天面试先到这里,你先回去等告诉。
对HashMap了解不深,没有将知识点发散的思维。
这一年阿巴阿巴发奋图强,再次约面。
<Center>当场发offer</Center>
面试官: HashMap理解吗?来谈谈你对这块的了解。
阿巴阿巴: 嗯嗯好,先从HashMap的构造开始吧,HashMap是一种散列表,以Key/Value模式存储,Key和Value都能够为空,在JDK 1.7时是由数组+链表组成,JDK 1.8则由数组+链表+红黑树组成,这里次要介绍下JDK 1.8版本的HashMap,初始默认的容量是16,负载因子是0.75,当链表上的元素大于8且数组容量大于64时链表进行红黑树化,当红黑树上元素缩小到6时,红黑树会进化为链表。
阿巴阿巴: 数组的查问效率是O(1),链表的查问效率是O(N),红黑树的查问效率是O(logN)。
阿巴阿巴: 还有,HashMap的容量必须是2的次幂,在构造方法中传入的容量如果不是2的次幂,那么HashMap会调用tableSizeFor()办法来获取一个最靠近传入容量且大于传入容量的2的次幂的值,比方传入的容量是17则tableSizeFor()会返回32。
面试官: 不错不错。
阿巴阿巴: HashMap空参数的构造方法创立进去的HashMap对象是不会初始化空间的,当应用空参构造方法创立出对象后,HashMap将在第一次插入元素时进行空间的初始化。
// 空参构造方法public HashMap(){this.loadFactor = DEFAULT_LOAD_FACTOR;}
阿巴阿巴: HashMap次要有2个重要办法,put()/get(),put()办法就是将元素无序的退出到HashMap中,也就是无奈保障元素的插入程序,get办法就是获取HashMap中的元素。
阿巴阿巴: 当元素进行put时,首先要计算key的Hash值,为了更加扩散,获取hash值后,HashMap会让hash值的高16位与hash进行异或。
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
阿巴阿巴: 而后判断HashMap有没有进行初始化,如果没有则进行初始化,再找到Key对应数组的地位,如果该地位没有元素则直接插入,如果有元素则判断是不是key与所在元素的key是不是统一,统一则新值替换旧值,如果不统一持续遍历这个节点下的链表或红黑树。
阿巴阿巴: 如果遍历过程中有元素的key与所在元素的key是统一的则新值替换旧值,否则将改元素退出到链表或红黑树中。
阿巴阿巴: get()办法首先计算key的hash值,而后找到hash对应数组中的地位的第一个元素,判断key是否统一,如果统一则返回否则持续查找这个元素下的链表或红黑树。
面试官: HashMap的扩容你理解吗?
阿巴阿巴: HashMap的扩容会调用resize()办法,扩容阈值为以后容量 * 负载因子,如果默认状况下hashMap容量为16,负载因子是0.75,则元素个数大于12就会触发扩容,resize()这个办法会先判断HashMap是不是初始化了,扩容的时候会创立一个新的数组,而后旧数组中的元素进行搬移,JDK1.7 的HashMap在并发场景下扩容有可能会造成死循环,cpu飙升100%。
面试官: 嗯,那你晓得为啥链表转红黑树的阈值是8吗?
阿巴阿巴: 哇,这个啊,这个在HashMap源码里有介绍,简略翻译就是:在应用散布良好的哈希码时,树是很少被应用的。现实状况下,随机哈希码遵循泊松散布,从下面给出的数据看,一个链表上有八个节点的概率为0.00000006 这个值要小于千万分之一。当这个阀值为8曾经很小了,所以这就是阈值选8的起因。
面试官: 你刚有讲在put()/get()办法中要判断元素是否统一,那是如何判断元素统一的呢?
阿巴阿巴: 先判断hash值是不是相等,如果相等再进行equals()判断,如果仍相等,则认为这两个元素统一。
面试官: 好的,今天来下班。
阿巴阿巴: 嗯嗯,再见!
总结
对罕用办法及过程进行了解说,以及波及到的一些细节进行了论述,发散了一些知识点。面试不要慌记住上面六点即可。
- 1、版本打好预防针(1.7\1.8版本)
- 2、数据结构没法跑(数组 + 链表 + 红黑树)
- 3、内置属性少不了(初始容量16、负载因子0.75、树化阈值8、树转链表阈值6、扩容大小2倍)
- 4、put/get要记牢(把根本的put、get流程记牢)
- 5、扩容办法不忘掉(扩容办法也要晓得流程、并发环境下1.7版本扩容会造成死锁)
- 6、边边角角都够到(比照了hash为啥还要比照equals办法,树化阈值为啥是8,key和value能为空吗,扩容肯定是达到阈值能力扩容吗)