在Java的面试中,HashMap知识点被问到的可能性非常大。下面就我对其理解以及整理资料如下:
1、谈一下HashMap的工作原理
HashMao是基于hashing的原理(源码hash算法的本质:取key的hashCode值、高位运算(高16bit不变,低16bit作异或运算)、取模运算((n-1)&hash)),通过put方法存储对象到HashMap中,使用get方法从HashMap中获取对象。当给put方法传递键和值时,先对键调用hashCode方法,返回hashcode值用于找到bucket位置来存储Entry对象。当获取对象时,通过对象的equals方法找到正确的键值对,然后返回值对象。
HashMap内部结构组成图:
2、当两个对象的hashcode值相同,怎么办呢?
由于hashcode值相同,所以这两个对象的bucket位置是相同的,这时候为产生“碰撞”,我们可以使用链表存储对象,就是说Entry存储在链表中。找到bucket位置后,调用keys.equals( )方法找到链表中正确的结点,最终找到要找的值对象。
3、HashMap的初始容量是多少?其权衡策略是怎么样的?
HashMap的默认容量是16。其权衡策略是动态分配桶的数量。
如果:HashMap的大小 > HashMap的容量 * 加载因子 |
那么:HashMap中的Entry[] table 的容量扩成为当前的一倍;然后重新将以前桶中的Entry<key,value>链表重新分配到各个桶中 |
容量:指HashMap内部Entry[] table线性数组的长度;
加载因子:是一个经验值,一般取值为0.75;
阀值:容量 * 加载因子;
4、权衡策略中调整HashMap大小,存在什么问题吗?
当重新调整HashMap大小的时候,在多线程的情况下,可能产生条件竞争。因为如果两个线程都发现HashMap需要重新调整大小,它们会同时试着调整大小。在调整大小的时候,存储在链表中的元素的次序会反过来,这是因为移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在链表的头部。这是为了避免尾部遍历。如果条件竞争发生了,那么就进入死循环了。(在多线程环境下,存在同时其他的元素也在进行put操作,如果hash值相同,可能出现在同一个数组下用链表表示,造成闭环,导致get时,出现死循环)