本人今年参加了很多面试,也有幸拿到了一些大厂的offer,整理了众多面试资料,后续还会分享众多面试资料,感兴趣的朋友可收藏+关注。由于时间有限,只能每天整理一点,分享一点儿!
现分享如下:
1. HashMap原理
HashMap是非常频繁面试问的题目,一定要好好理解,最好是查看源码吃透它。
HashMap的底层实现是使用:数组+链表/红黑树。
HashMap内部维护了一个存储数据的Entry数组,HashMap采用链表解决冲突,每一个Entry本质上是一个单向链表。当准备添加一个key-value对时,首先通过hash(key)方法计算hash值,然后通过indexFor(hash,length)求该key-value对的存储位置,计算方法是先用hash&0x7FFFFFFF后,再对length取模,这就保证每一个key-value对都能存入HashMap中,当计算出的位置相同时,由于存入位置是一个链表,则把这个key-value对插入链表头
在jdk1.8之后hashmap已经优化了hashmap的单链表,当数据存储到8位之后内部采用红黑树结构来存储数据,这样会比单链表更快。
2. 常考点
Q1:Table的初始化
通过阅读源码可发现,HashMap有四种构造方式:
· 根据指定的initialCapaccity和loadFactor实例化一个空对象;
· 通过指定的 initialCapacity 和 默认的 loadFactor(0.75) 实例化一个空的
HashMap 对象
· 通过默认的initialCapacty和模型的loadFactor(0.75)实例化一个空的HashMap
· 通过指定的Map对象实例化一个HashMap对象
通过源码可以知道:实例化的时候未进行table的初始化,而什么时候初始化呢?一般情况下,在第一次对table进行put时,调用resize方法时,进行table的初始化。(这是一种懒加载思想)。一般情况下,初始化table.length=16, 阈值threadhold=12,当存放到第13个元素时进行扩容。(threadhold=capacity*loadFactor)
Q2: table的扩容方式
还是在调用resize()时进行扩容,扩容的方式是:当size>threshold时进行扩容,扩容之后的 table.length = table.lenght2, threshold = threshold2
Q3: Table的length为什么是2的n次幂
是为了能利用位运算(&)来求 key 的下标,而 h&(length-1) 是为了充分利用 table 的空间,并减少 key 的碰撞;
Q4: Table的取模运算为什么是e.hash & (capacity-1)
因为一般的取模运算是e.hash % capacity,而e.hash &(capacity-1) = e.has%capacity
3. Hashmap和Hashtable的异同
(1)相同点
· 两者都是基于哈希表实现的,每一个元素是一个key-value对,内部通过单链表解决访问冲突,容量不足时会自动增长。
· 两者都实现了序列化Serializable接口,支持序列化,实现了Cloneable接口,可被克隆。
(2)不同点
· HashMap是非线程安全的,Hashtable是线程安全的;
· HashMap的key和value允许为null,而HashTable不允许。