HashMap的相关面试题
哈希表的理解
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表或哈希表
JDK8中HashMap为什么到8转为红黑树 到6转为链表?
TreeNode(红黑树中)占用空间是普通Node(链表中)的两倍,为了时间和空间的权衡。
如果是7,那么在极端情况下比如在同一个哈希桶中,对长度为8的哈希桶进行频繁的删除和插入,会频繁的 树化<=>非树化。
HashMap的初始大小为什么是16?加载因子为什么是0.75?扩容倍数为什么是2?扩容策略?
HashMap的初始大小为什么是16?
确定桶下标的最后一步是将 key 的 hash 值对桶个数取模:hash%capacity,如果能保证 capacity 为 2 的 n 次方,那么就可以将这个操作转换为位运算。位运算的代价比求模运算小的多,因此在进行这种计算时用位运算的话能带来更高的性能。16=2^4,不至于过大也不至于过小。
加载因子为什么是0.75?
提高空间利用率和 减少查询成本的折中,主要是泊松分布,0.75的话碰撞最小。加载因子过高,提高了空间利用率,但同时也增加了查询时间成本;加载因子过低,虽然可以减少查询时间成本,但是空间利用率很低。
扩容倍数为什么是2?
HashMap的初始容量是2的n次幂,扩容也是2倍的形式进行扩容,是因为容量是2的n次幂,可以使得添加的元素均匀分布在HashMap中的数组上,减少hash碰撞,避免形成链表的结构让查询效率降低!
扩容策略?
JDK7中会重新计算hash,JDK8中不需要重新计算hash,只需要看原来新增的那个hash值新增的那个bit位是0还是1,是0的话索引不变,是1的话索引变成"原索引+oldCap"
hashMap插入数据的过程
1.首先判断是否进行了初始化,如果没有则进行resize();
2.通过传入键值对里面的key获取hashcode和容量,通过hash()方法得到数组下标,然后通过该下标获取该哈希桶的头节点;
3.如果没有发生哈希碰撞(头节点为null),直接进行插入操作;
4.如果发生哈希碰撞(头节点不为null),分为两种情况:
(1) 与桶内某个元素equals(),返回true就覆盖;
(2)与桶内所有元素都不相等,执行插入操作,可能是链表或者红黑树;
5.链表新增操作后,会有两个判断:
(1) 哈希桶是单链表结构,桶内数量达到8并且元素数量大于等于64,会转为红黑树;
(2)元素数量达到容量的0.75,则进行resize();
hashMap获取数据的过程
1.调用key的hashcode方法,根据返回值定位到数组下标;
2.判断该数组下标对应的头节点是否为null,如果为null,则返回null;
3.如果头节点不为null,首先判断是不是红黑树,如果是,则调用红黑树的方法,否则遍历链表,比较每个元素的key,调用key的equals()与被查询的key比较,相等就返回该key对应的value;遍历完链表都没有相等的就返回null;