HashMap整理考点

什么是HashMap,java常用的键值对集合,键唯一值可重复
底层基于哈希表 查找平均O(1)快得像闪电
底层结构?
数组+链表+红黑树
数组是主体,链表和红黑树是来解决哈希冲突的。
为啥又要链表又要红黑树?
1.7之前只有链表
1.8开始链表太长就转红黑树
因为红黑树能把最坏情况从O(n)降到O(log n)
就像排队100人和排队10人的区别
那为啥不用AVL树
AVL树是强迫症患者,动不动就旋转
红黑树平衡策略相对宽松,是工程界的老油条
性能好,还不累。
红黑树那么牛,为什么还留着链表?
因为红黑树胖呀,红黑树节点大小是普通节点的两倍 能省则省
链表啥时候转红黑树?
链表长度大于等于8且数组长度大于等于64
为啥数组要大于等于64
两个原因:避免频繁树化--数组小的时候 扩容就能解决冲突,别急着树化
减少内存占用--红黑树节点是两倍大,能省则省。
那链表大于等于8但数组小于64怎么办
扩容。直接翻倍,重新哈希,让冲突自动消失。
为啥阈值是8
源码注释说了,和泊松分布有关
在0.75负载因子下,链表长度到8的概率极低。
基本上不会触发,选8是为了时间和空间平衡
红黑树还能转回链表么
会。当树节点小于等于6的时候,又从红黑树转回链表
为啥不是小于等于8就转?
要留个缓冲的余地,避免重复横跳:8-9树化,9-8反树化,再加又树化
树化和反树化都有开销,不能让系统像仰卧起坐一样折腾。
负载因子为啥是0.75?
源码注释说了,是空间和时间的平衡
设太小(0.5)冲突少查询快,但是频繁扩容
设太大(1):省空间,但查得慢。
0.75是实践下来最折中的选择,大多数场景都够用。
put流程说一下?
先计算哈希再找桶,桶里有值再eaqual判断,桶是空的直接插入,是key就替换,不是就插尾部,顺便检查一下要不要树化或扩容
为啥尾部插入?1.7版本不是头插么?
1.7头插法有个坑,多线程扩容可能导致链表成环,导致死循环CPU 100%
1.8改成尾插法,虽然多线程还是不能用,但是至少不会把自己绕进去
扩容机制讲讲?
默认16,负载因子0.75 阈值12,第13个元素插入就触发扩容
新建两倍大小的数组,把所有元素重新哈希搬运过去
为啥是2倍?
为了让容量始终保持2的幂,这样可以用(n-1)&hash位运算,快速定位下标
比取余运算要快多了
1.8扩容优化了啥?
1.7是全部重新哈希,1.8只要看哈希值的某一位,是0就留在原位,是1就挪到“原位置+原数组大小”不需要重新计算哈希,搬运更快。
1.8还有啥改动?
三大改动:哈希函数优化:高16位和低16位异或分布更均匀
扩容迁移优化:刚说的头插改尾插:防止成环
hashMap和hashSet的区别?
hashSet的底层就是hashMap
元素存在HashMap的键里,值都是一个固定的常量
HashMap保证顺序么?
不保证,要插入顺序就用LinkedHashMap
要排序用TreeMap.
LinkedHashMap用过么?
用过。实现LRU缓存的时候,一行代码搞定。
TreeMap用过么
用过,对接第三方接口,参数排序加密的时候,TreeMap自动排序,很方便。

posted @ 2026-06-10 10:16  堭鍙銤  阅读(22)  评论(0)    收藏  举报