HashMap 基本实现原理

91 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

在面试中经常会被问到HashMap的原理,HashMap是怎么实现的?

HashMap在日常开发中经常会使用到,其凭借着高效的增删改查操作得到了开发者的青睐。

1. 基本数据结构

首先我们需要知道HashMap的数据结构,HashMap随着JDK的发展,也存在着一定的区别。

  • JDK1.7之前
    • 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对象,并向里面放入了一个键值对,那么存储流程如下:

  1. 将传入键值对的key值通过哈希函数hash()方法计算出哈希值(这里注意哈希函数不是hashCode())
  2. 之后将键值对存入数组下标为哈希值的位置
  3. 由于数组存放的是链表,那么存入的过程中
  4. 在JDK1.7之前,采用的是头插法插入到链表的头部
    1. 在JDK1.8之后,采用的是尾插法插入到链表的尾部
  5. 当存入的元素已经存在于HashMap中,那么新的键值对会替换掉旧的键值对,而不是重新插入到链表当中

2. get()

了解了HashMap如何存储元素,接下来可以了解如何检索HashMap的元素

  1. 根据哈希函数计算出需要检索key值的哈希值
  2. 找到数组中下标为哈希值的链表
  3. 逐个对比链表中键值对的key值是否与需要检索的key值相等
  4. 若存在相等key值则返回对应位置的value值,若不存在则返回null

3. remove()

在HashMap中删除元素,跟上述两种方法类似,一样计算出key的哈希值,找到相应的链表在匹配key找到相应的键值对进行删除

2. 红黑树存储优化

在JDK1.8之后,键值对不再是全部以链表的方式存储,系统会根据当前桶中元素个数来动态更换存储结构

  • 若链表元素超过8个时,链表会自动转化为红黑树
  • 若链表元素少于等于6个时候,红黑树会自动转化为链表

3. HashMap特点

  • HashMap的遍历顺序是不确定的
  • HashMap并非线程安全,当多个线程同时写入HashMap时候,会导致数据不一定

如有错误,欢迎在评论区指出!