服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - java 中的HashMap的底层实现和元素添加流程

java 中的HashMap的底层实现和元素添加流程

2022-12-06 15:23Java中文社群 Java教程

这篇文章主要介绍了java 中的HashMap的底层实现和元素添加流程,HashMap 是使用频率最高的数据类型之一,同时也是面试必问的问题之一,尤其是它的底层实现原理,下文更多详细内容,需要的小伙伴可以参考一下

前言:

HashMap 是使用频率最高的数据类型之一,同时也是面试必问的问题之一,尤其是它的底层实现原理,既是常见的面试题又是理解 HashMap 的基石,所以重要程度不言而喻。

HashMap 底层实现

HashMap 在 JDK 1.7 和 JDK 1.8 的底层实现是不一样的,在 JDK 1.7 中,HashMap 使用的是数组 + 链表实现的,而 JDK 1.8 中使用的是数组 + 链表或红黑树实现的

HashMap 在 JDK 1.7 中的实现如下图所示:

java 中的HashMap的底层实现和元素添加流程

HashMap 在 JDK 1.8 中的实现如下图所示:

java 中的HashMap的底层实现和元素添加流程

我们本文重点来学习主流版本 JDK 1.8 中的 HashMap。HashMap 中每个元素称之为一个哈希桶(bucket),

哈希桶包含的内容有 4 个:

  • hash 值
  • key
  • value
  • next(下一个节点)

HashMap 插入流程

HashMap 元素新增的实现源码如下(下文源码都是基于主流版本 JDK 1.8):

public V put(K key, V value) {
  // 对 key 进行哈希操作
  return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
             boolean evict) {
  Node<K,V>[] tab; Node<K,V> p; int n, i;
  // 哈希表为空则创建表
  if ((tab = table) == null || (n = tab.length) == 0)
      n = (tab = resize()).length;
  // 根据 key 的哈希值计算出要插入的数组索引 i
  if ((p = tab[i = (n - 1) & hash]) == null)
      // 如果 table[i] 等于 null,则直接插入
      tab[i] = newNode(hash, key, value, null);
  else {
      Node<K,V> e; K k;
      // 如果 key 已经存在了,直接覆盖 value
      if (p.hash == hash &&
          ((k = p.key) == key || (key != null && key.equals(k))))
          e = p;
      // 如果 key 不存在,判断是否为红黑树
      else if (p instanceof TreeNode)
          // 红黑树直接插入键值对
          e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
      else {
          // 为链表结构,循环准备插入
          for (int binCount = 0; ; ++binCount) {
              // 下一个元素为空时
              if ((e = p.next) == null) {
                  p.next = newNode(hash, key, value, null);
                  // 转换为红黑树进行处理
                  if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                      treeifyBin(tab, hash);
                  break;
              }
              //  key 已经存在直接覆盖 value
              if (e.hash == hash &&
                  ((k = e.key) == key || (key != null && key.equals(k))))
                  break;
              p = e;
          }
      }
      if (e != null) { // existing mapping for key
          V oldValue = e.value;
          if (!onlyIfAbsent || oldValue == null)
              e.value = value;
          afterNodeAccess(e);
          return oldValue;
      }
  }
  ++modCount;
  // 超过最大容量,扩容
  if (++size > threshold)
      resize();
  afterNodeInsertion(evict);
  return null;
}

上述的源码都添加了相应的代码注释,简单来说 HashMap 的元素添加流程是,先将 key 值进行 hash 得到哈希值,根据哈希值得到元素位置,判断元素位置是否为空,如果为空直接插入,不为空判断是否为红黑树,如果是红黑树则直接插入,否则判断链表是否大于 8,且数组长度大于 64,如果满足这两个条件则把链表转成红黑树,然后插入元素,如果不满足这两个条件中的任意一个,则遍历链表进行插入,

它的执行流程如下图所示:

java 中的HashMap的底层实现和元素添加流程

为什么要将链表转红黑树?

JDK 1.8 中引入了新的数据结构红黑树来实现 HashMap,主要是出于性能的考量。因为链表超过一定长度之后查询效率就会很低,它的时间复杂度是 O(n),而红黑树的时间复杂度是 O(logn),因此引入红黑树可以加快 HashMap 在数据量比较大的情况下的查询效率。

哈希算法实现

HashMap 的哈希算法实现源码如下:

static final int hash(Object key) {
  int h;
  return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

其中,key.hashCode() 是 Java 中自带的 hashCode() 方法,返回一个 int 类型的散列值,后面 hashCode 再右移 16 位,正好是 32bit 的一半,与自己本身做异或操作(相同为 0,不同为 1),主要是为了混合哈希值的高位和低位,增加低位的随机性,这样就实现了 HashMap 的哈希算法。

总结

HashMap 在 JDK 1.7 时,使用的是数组 + 链表实现的,而在 JDK 1.8 时,使用的是数组 + 链表或红黑树的方式来实现的,JDK 1.8 之所以引入红黑树主要是出于性能方面的考虑。HashMap 在插入时,会判断当前链表的长度是否大于 8 且数组的长度大于 64,如果满足这两个条件就会把链表转成红黑树再进行插入,否则就是遍历链表插入。

到此这篇关于java 中的HashMap的底层实现和元素添加流程的文章就介绍到这了,更多相关Java中的HashMap内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://juejin.cn/post/7052492909408419853

延伸 · 阅读

精彩推荐
  • Java教程Spring MVC 自定义数据转换器的思路案例详解

    Spring MVC 自定义数据转换器的思路案例详解

    本文通过两个案例来介绍下Spring MVC 自定义数据转换器的相关知识,每种方法通过实例图文相结合给大家介绍的非常详细,需要的朋友可以参考下...

    Training.L6912022-01-06
  • Java教程Java 高并发四:无锁详细介绍

    Java 高并发四:无锁详细介绍

    本文主要介绍Java 高并发无锁的知识,这里整理了 1.无锁类的原理详解 2.无锁类的使用的知识,并讲解其原理,有需要的小伙伴可以参考下...

    Hosee2932020-06-14
  • Java教程mybatis条件语句中带数组参数的处理

    mybatis条件语句中带数组参数的处理

    这篇文章主要介绍了mybatis条件语句中带数组参数的处理方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    luffy545910542021-12-28
  • Java教程解析Java的Spring框架的BeanPostProcessor发布处理器

    解析Java的Spring框架的BeanPostProcessor发布处理器

    这篇文章主要介绍了Java的Spring框架的BeanPostProcessor发布处理器,Spring是Java的SSH三大web开发框架之一,需要的朋友可以参考下 ...

    goldensun3812020-03-08
  • Java教程Java中值传递的深度分析

    Java中值传递的深度分析

    这篇文章主要给大家介绍了关于Java中值传递的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋...

    昆明--菜鸟入门9842021-07-29
  • Java教程源码解析带你了解LinkedHashMap

    源码解析带你了解LinkedHashMap

    大多数情况下,只要不涉及线程安全问题,Map基本都可以使用HashMap,不过HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序。...

    JavaEdge.10552022-01-03
  • Java教程在idea中创建SpringBoot项目

    在idea中创建SpringBoot项目

    这篇文章主要介绍了在idea中创建SpringBoot项目,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    马尼马努7272021-05-13
  • Java教程kafka与storm集群环境的安装步骤详解

    kafka与storm集群环境的安装步骤详解

    这篇文章主要给大家介绍了关于kafka与storm集群环境安装步骤的相关资料,两者并不是一定联系的,写在一起主要是因为两个都是有zookeeper管理的,文中通过...

    虚无境11322021-03-27