1、HashMap 默认初始大小
16
为什么是16?因为16是2的倍数,可以减少哈希冲突。
2、如何减少哈希冲突
为了减少hash值的碰撞,需要实现一个尽量均匀分布的hash函数,在HashMap中通过利用key的hashcode值,来进行位运算
公式:index = e.hash & (newCap - 1)
3、发生哈希冲突的时候,怎么办?
链表
4、HashMap可以有null 值吗?
允许使用 null 值和 null 键。
5、HashMap的加载因子为什么是 0.75?
扩容时机:
假如加载因子是 0.5,HashMap 的初始化容量是 16,那么当 HashMap 中有 16*0.5=8 个元素时,HashMap 就会进行扩容。
原因有二:
(1)当加载因子设置较大时,扩容的门槛就高,扩容发生的频率低,占用的空间会小,但此时Hash冲突的几率提升,因此需要更复杂的数据结构(链表等)来存储元素,操作数据的时间增加,运行效率降低;
(2)而当加载因子值较小时,扩容的门槛会低,会占用更多的空间,元素的存储稀疏,发生哈希冲突的可能性较小,因此操作性能会比较高。
(3)所以,就取了一个 0.5 到 1.0 的平均数 0.75 作为加载因子
6、HashMap和Hashtable有什么区别?
区别 | HashMap | Hashtable |
---|---|---|
初始大小 | 16 | 11 |
加载因子 | 0.75 | 0.75 |
扩容 | oldsize * 2 | oldsize * 2 + 1 |
底层数据结构 | 红黑树 + 数组 + 链表 | 数组+链表 |
允许键或值为 null | 是 | 否 |
部分API不同 | 无contains()/toString() | 有contains()/toString() |
同步性 | 非同步 | 同步 |
适用的线程 | 单线程 | 多线程 |
性能 | 好 | 差 |
7、HashMap 的底层实现
JDK8之前是:数组+链表
JKD8以及之后是:数组+链表+红黑树
数组+链表:
所有的HashMap的数据都是存放在数组上的,当发生哈希冲突的时候,就会把冲突的数据存放在链表上;当链表长度大于等于8的时候,将链表转换成红黑树方便查找。
8、红黑树的特性
(1)根节点是黑色的
(2)所有的叶子节点都是黑色的,并且叶子节点都不存储数据
(3)任何相邻的两个节点都不能同时为红色
(4)任意节点到达其可到达的叶节点间都包含相同数目的黑色节点
红黑树是一颗近乎平衡的二叉查找树。
任何一条路径不会比其他路径长出两倍;
树的高度≈log(n); 最多是 2*log(n + 1);
插入、删除、查找的时间复杂度≈log(n);
AVL树为了保持严格的平衡,每次插入删除都会做调整;红黑树不必保持严格平衡,所以对于频繁的插入删除操作,红黑树的效率更高;
9、AVL 树的特性:
AVL树查找效率: < log(n)
AVL树为了保持严格的平衡,每次插入删除都会做调整;
红黑树不必保持严格平衡,所以对于频繁的插入删除操作,红黑树的效率更高