开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情
在面试中经常会被问到HashMap的原理,HashMap是怎么实现的?
HashMap在日常开发中经常会使用到,其凭借着高效的增删改查操作得到了开发者的青睐。
1. 基本数据结构
首先我们需要知道HashMap的数据结构,HashMap随着JDK的发展,也存在着一定的区别。
- JDK1.7之前
- HashMap是
数组+链表的存储结构- 在链表插入元素时采用头插法
- HashMap是
- JDK1.8之后
- 变成了
数组+链表+红黑树的存储结构 - 当HashMap的链表长度过长时则会采用红黑树存储,因为红黑树的检索更高效
- 在链表插入元素时采用了尾插法
- 变成了
2. 基本存储流程
HashMap<String, Integer> ageMap = new HashMap<>();
ageMap.put("LiHua", 23);
System.out.println("LiHua age: " + ageMap.get("LiHua"));
ageMap.remove("LiHua");
System.out.println("LiHua age: " + ageMap.get("LiHua"));
1. put()
在上述代码中,我们实例化一个HashMap对象,并向里面放入了一个键值对,那么存储流程如下:
- 将传入键值对的key值通过哈希函数
hash()方法计算出哈希值(这里注意哈希函数不是hashCode()) - 之后将键值对存入数组下标为哈希值的位置
- 由于数组存放的是链表,那么存入的过程中
- 在JDK1.7之前,采用的是头插法插入到链表的头部
- 在JDK1.8之后,采用的是尾插法插入到链表的尾部
- 当存入的元素已经存在于HashMap中,那么新的键值对会替换掉旧的键值对,而不是重新插入到链表当中
2. get()
了解了HashMap如何存储元素,接下来可以了解如何检索HashMap的元素
- 根据哈希函数计算出需要检索key值的哈希值
- 找到数组中下标为哈希值的链表
- 逐个对比链表中键值对的key值是否与需要检索的key值相等
- 若存在相等key值则返回对应位置的
value值,若不存在则返回null
3. remove()
在HashMap中删除元素,跟上述两种方法类似,一样计算出key的哈希值,找到相应的链表在匹配key找到相应的键值对进行删除
2. 红黑树存储优化
在JDK1.8之后,键值对不再是全部以链表的方式存储,系统会根据当前桶中元素个数来动态更换存储结构
- 若链表元素超过8个时,链表会自动转化为红黑树
- 若链表元素少于等于6个时候,红黑树会自动转化为链表
3. HashMap特点
- HashMap的遍历顺序是不确定的
- HashMap并非线程安全,当多个线程同时写入HashMap时候,会导致数据不一定
如有错误,欢迎在评论区指出!