Java中HashMap的put方法实现原理

一、数据结构介绍

HashMap是Java中常用的一种集合,是基于一定的hash算法实现的Key-value数据结构。HashMap类继承于AbstractMap类,实现了Map接口。HashMap的底层实现是数组加链表或红黑树,通过key的hash值来找到其在数组中的位置,然后将其存储在该位置的链表或红黑树中。

public class HashMap extends AbstractMap
    implements Map, Cloneable, Serializable {
        ...
    }

二、put方法

put方法是HashMap中最关键的方法之一,它负责将一个键值对存储到Map中。put方法有两个参数,第一个是key,第二个是value,该方法的返回值是被替换的value,如果之前没有关联的value则返回null。

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

可以看到,put方法的核心是putVal方法,该方法对外部不可见,它将key-value对插入到HashMap中,并且可以进行扩容和重新哈希处理。

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
            boolean evict) {
    Node[] tab; Node p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode)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;
                }
                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;
}

三、put实现原理

put方法主要通过以下几个步骤实现:

  1. 如果table为null,或者table数组长度为0,执行resize方法进行初始化,否则直接用当前table数组存储值。
  2. 通过(key.hash) & (n-1)计算key的哈希值,并找到它在table中需要存储的位置 i。
  3. 检查table[i]的这个位置是否已经有了值(e),如果没有,就把新的键值对放到table[i]的位置上。
  4. 如果已经存在节点e,即table[i]位置已被占用,则需要进一步判断e和新插入元素的key是否相同,如果相同,则覆盖原本的值,否则,需要判断e所在节点的类型,如果是红黑树节点,则插入红黑树,否则在链表末尾追加节点。
  5. 如果链表长度超过TREEIFY_THRESHOLD(默认值为8)时,则将链表转化成红黑树。TREEIFY_THRESHOLD是为了避免链表过长导致查询时间复杂度增加。
  6. 在插入节点后,判断是否超过容量阈值(threshold),如果超过,进行扩容操作,将table数组长度翻倍。

四、实战应用

下面是一个简单的HashMap使用示例,通过put方法向map中存储数据。

HashMap map = new HashMap();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
System.out.println(map.get(1)); //"one"
System.out.println(map.get(2)); //"two"
System.out.println(map.get(3)); //"three"

五、总结

本篇文章介绍了Java中HashMap的put方法实现原理,分别通过数据结构介绍、put方法、put实现原理和实战应用等方面进行了详细阐述。

为了保证HashMap的效率,需要在设计key的时候尽量避免哈希冲突,这样可以减少链表的长度,提高HashMap的查询效率。同时需要注意TREEIFY_THRESHOLD的值,这个值设置过小会导致链表膨胀成红黑树的过快,大大降低查询性能。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/182034.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-11-24 06:17
下一篇 2024-11-24 06:17

相关推荐

  • Java JsonPath 效率优化指南

    本篇文章将深入探讨Java JsonPath的效率问题,并提供一些优化方案。 一、JsonPath 简介 JsonPath是一个可用于从JSON数据中获取信息的库。它提供了一种DS…

    编程 2025-04-29
  • java client.getacsresponse 编译报错解决方法

    java client.getacsresponse 编译报错是Java编程过程中常见的错误,常见的原因是代码的语法错误、类库依赖问题和编译环境的配置问题。下面将从多个方面进行分析…

    编程 2025-04-29
  • Java腾讯云音视频对接

    本文旨在从多个方面详细阐述Java腾讯云音视频对接,提供完整的代码示例。 一、腾讯云音视频介绍 腾讯云音视频服务(Cloud Tencent Real-Time Communica…

    编程 2025-04-29
  • Java Bean加载过程

    Java Bean加载过程涉及到类加载器、反射机制和Java虚拟机的执行过程。在本文中,将从这三个方面详细阐述Java Bean加载的过程。 一、类加载器 类加载器是Java虚拟机…

    编程 2025-04-29
  • Java Milvus SearchParam withoutFields用法介绍

    本文将详细介绍Java Milvus SearchParam withoutFields的相关知识和用法。 一、什么是Java Milvus SearchParam without…

    编程 2025-04-29
  • 解决.net 6.0运行闪退的方法

    如果你正在使用.net 6.0开发应用程序,可能会遇到程序闪退的情况。这篇文章将从多个方面为你解决这个问题。 一、代码问题 代码问题是导致.net 6.0程序闪退的主要原因之一。首…

    编程 2025-04-29
  • ArcGIS更改标注位置为中心的方法

    本篇文章将从多个方面详细阐述如何在ArcGIS中更改标注位置为中心。让我们一步步来看。 一、禁止标注智能调整 在ArcMap中设置标注智能调整可以自动将标注位置调整到最佳显示位置。…

    编程 2025-04-29
  • Python中init方法的作用及使用方法

    Python中的init方法是一个类的构造函数,在创建对象时被调用。在本篇文章中,我们将从多个方面详细讨论init方法的作用,使用方法以及注意点。 一、定义init方法 在Pyth…

    编程 2025-04-29
  • Python创建分配内存的方法

    在python中,我们常常需要创建并分配内存来存储数据。不同的类型和数据结构可能需要不同的方法来分配内存。本文将从多个方面介绍Python创建分配内存的方法,包括列表、元组、字典、…

    编程 2025-04-29
  • Java 8中某一周的周一

    Java 8是Java语言中的一个版本,于2014年3月18日发布。本文将从多个方面对Java 8中某一周的周一进行详细的阐述。 一、数组处理 Java 8新特性之一是Stream…

    编程 2025-04-29

发表回复

登录后才能评论