HashMap的工作原理是近年来常见的Java面试题。几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之间的区别,那么为何这道面试题如此特殊呢?是因为这道题考察的深度很深。这题经常出现在高级或中高级面试中。投资银行更喜欢问这个问题
在JDK1.6和JDK1.7,hashMap使用数组+链表实现(使用链表来处理hash冲突),同一个hash值的链表都存储在一个链表里。
但是当一个数组元素中,链表的节点过多,通过key值去查找效率会很低。
在JDK1.8之后,当链表阈值超过8时,就会将链表转换成红黑树。
1.当我们push(key,value)的时候,先对key调用hashCode()方法,返回的hash值用于找到bucket位置(数组),存储Entry对象(key和value)链表形式。
2.如果不同的key发生hash冲突的时候,因为bucket位置相同,所以将Entry对象以链表形式存储。
3.如果不同的key,而两个hashCode相同,如何通过get(key)获取对象。会遍历链表,通过keys.equals(),去找唯一的对象。
4.链表是一个对象引用下一个对象。那么并发执行,可能会发生替换。
如果HashMap的大小超过了负载因子的容量。
负载因子(load factor)
默认0.75,也就是说当一个map填满了75%的bucket的时候,和其他集合类一样,创建原来map的2倍大小的bucket,将原来的对象放入。
重新调整HashMap存在什么问题?
存在条件竞争,因为如果两个线程都发现HashMap调整大小,它们会同时尝试调整大小。存储在链表的元素的次序会反过来,因为移动到新的bucket位置时,HashMap将不会将元素放在链表尾部,而是放在头部。这是为了避免尾部遍历。如果竞争了就死循环了。