首页 > 编程语言 >HashMap 的底层原理和源码分析

HashMap 的底层原理和源码分析

时间:2023-06-29 22:32:23浏览次数:35  
标签:hash HashMap 哈希 链表 源码 key null 底层


tip:作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。

推荐:体系化学习Java(Java面试专题)


文章目录

  • 一、HashMap 的底层原理
  • 二、put方法源码分析
  • 三、get 方法源码分析
  • 四、remove 方法源码分析


一、HashMap 的底层原理

HashMap 是 Java 中常用的一种数据结构,它是基于哈希表实现的。下面是 HashMap 的底层原理:

HashMap 内部维护了一个数组,称为哈希表,每个元素都是一个链表的头结点,该链表被称为桶(bucket)。当我们向 HashMap 中添加一个元素时,首先会根据该元素的键值(key)计算出一个哈希值(hash code),然后根据哈希值确定该元素在数组中的位置,如果该位置上已经存在了元素,则将该元素添加到该位置上对应的桶中,如果该位置上没有元素,则创建一个新的桶,并将该元素添加到该桶中。

HashMap 的底层原理和源码分析_哈希算法

HashMap 的哈希值是通过调用键值的 hashCode 方法计算得到的。由于哈希值可能会发生冲突,因此每个桶中可能会有多个元素。当我们需要查找元素时,首先根据键值的哈希值确定该元素所在的桶,然后遍历该桶中的所有元素,找到与给定键值相等的元素并返回。

为了提高 HashMap 的查找效率,Java 8 中引入了红黑树(Red-Black Tree)的概念。当一个桶中的元素个数达到一定阈值(默认为 8)时,该桶中的元素将被转化为一棵红黑树,从而提高查找效率。当然,如果桶中的元素个数小于等于阈值,则仍然采用链表的方式进行存储。

HashMap 的扩容机制是在数组大小达到一定阈值(默认为 75%)时进行的。当数组大小达到阈值时,HashMap 会创建一个新的数组,将原数组中的元素重新哈希到新数组中,并将新数组作为 HashMap 的哈希表。这个过程需要重新计算每个元素在新数组中的位置,因此比较耗时。

HashMap 是非线程安全的,如果多个线程同时对 HashMap 进行修改,可能会导致数据不一致的情况。如果需要在多线程环境下使用 HashMap,可以使用 ConcurrentHashMap。

HashMap 的底层原理和源码分析_数组_02

二、put方法源码分析

public V put(K key, V value) {
   
    // 计算 key 的哈希值
    int hash = hash(key);
    
    // 根据哈希值和数组长度计算出 key 在数组中的位置
    int i = indexFor(hash, table.length);
    
    // 遍历该位置上的链表,查找是否已经存在该 key
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        // 如果该 key 已经存在,则更新其对应的 value,并返回旧的 value
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }
    
    // 如果该 key 不存在,则将其添加到链表的头部
    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

put 方法的主要流程如下:

  1. 计算 key 的哈希值。
  2. 根据哈希值和数组长度计算出 key 在数组中的位置。
  3. 遍历该位置上的链表,查找是否已经存在该 key,如果存在,则更新其对应的 value,并返回旧的 value。
  4. 如果该 key 不存在,则将其添加到链表的头部。

在添加元素时,HashMap 会将元素添加到链表的头部,这是因为在遍历链表时,我们通常会从头部开始遍历,这样可以提高查找效率。如果链表中已经存在该 key,则将其对应的 value 更新为新的值。如果链表中不存在该 key,则将其添加到链表的头部,并将 modCount 属性加 1,表示 HashMap 的结构已经发生了变化。

三、get 方法源码分析

public V get(Object key) {
    
    // 如果 key 为 null,则返回 null
    if (key == null)
        return getForNullKey();
    
    // 计算 key 的哈希值
    int hash = hash(key);
    
    // 根据哈希值和数组长度计算出 key 在数组中的位置
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
         e != null;
         e = e.next) {
        Object k;
        // 如果找到了对应的 key,则返回其对应的 value
        if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
            return e.value;
    }
    
    // 如果没有找到对应的 key,则返回 null
    return null;
}

get 方法的主要流程如下:

  1. 如果 key 为 null,则返回 null。
  2. 计算 key 的哈希值。
  3. 根据哈希值和数组长度计算出 key 在数组中的位置。
  4. 遍历该位置上的链表,查找是否存在对应的 key,如果存在,则返回其对应的 value。
  5. 如果链表中不存在对应的 key,则返回 null。

在查找元素时,HashMap 会根据 key 的哈希值确定其在数组中的位置,然后遍历该位置上的链表,查找是否存在对应的 key。如果存在,则返回其对应的 value;如果不存在,则返回 null。由于哈希值可能会发生冲突,因此同一个桶上可能会有多个元素,需要遍历链表才能找到对应的元素。

四、remove 方法源码分析

public V remove(Object key) {
    Entry<K,V> e = removeEntryForKey(key);
    return (e == null ? null : e.value);
}

final Entry<K,V> removeEntryForKey(Object key) {
   // 如果 key 为 null,则返回 null
   if (key == null)
       return null;
  
   // 计算 key 的哈希值
   int hash = hash(key);
   
   // 根据哈希值和数组长度计算出 key 在数组中的位置
   int i = indexFor(hash, table.length);
  
   // 遍历该位置上的链表,查找是否存在对应的 key
   Entry<K,V> prev = table[i];
   Entry<K,V> e = prev;
   while (e != null) {
       Entry<K,V> next = e.next;
       Object k;
       // 如果找到了对应的 key,则将其从链表中删除
       if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
           modCount++;
           size--;
           if (prev == e)
               table[i] = next;
           else
               prev.next = next;
           e.recordRemoval(this);
           return e;
       }
       prev = e;
       e = next;
   }
   
   // 如果没有找到对应的 key,则返回 null
   return null;
}

remove 方法的主要流程如下:

  1. 调用 removeEntryForKey 方法查找对应的 Entry 对象。
  2. 如果找到了对应的 Entry 对象,则将其从链表中删除,并返回其对应的 value。
  3. 如果没有找到对应的 Entry 对象,则返回 null。

在删除元素时,HashMap 会先调用 removeEntryForKey 方法查找对应的 Entry 对象,然后将其从链表中删除。如果找到了对应的 Entry 对象,则将其从链表中删除,并返回其对应的 value;如果没有找到对应的 Entry 对象,则返回 null。


标签:hash,HashMap,哈希,链表,源码,key,null,底层
From: https://blog.51cto.com/u_12748886/6578369

相关文章

  • ArrayList 的底层原理和源码分析
    tip:作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。推荐:体系化学习Java(Java面试专题)文章目录一、简介二、自动扩容机制三、add方法的源码分析四、addAll方法的源码分析五、set方法的源码分析六、remove方......
  • C# ModbusRtu或者TCP协议上位机源码,包括存储,数据到SQL SERVER数据库,趋势曲线图,数据报
    C#ModbusRtu或者TCP协议上位机源码,包括存储,数据到SQLSERVER数据库,趋势曲线图,数据报表,实时和历史报警界面,有详细注释,需要哪个协议版本原创文章,转载请说明出处,资料来源:http://imgcs.cn/5c/655313350668.html......
  • C# opc ua客户端实例源码,带ef6+sqlite
    C#opcua客户端实例源码,带ef6+sqlite。代码有完整的注解,及包括所有的链接库和程序结构思维图。纯学习资料原创文章,转载请说明出处,资料来源:http://imgcs.cn/5c/638904489888.html......
  • 2023年6月29日,测评机试题,Iterator底层,ListIterator底层,LinkedList底层
    1.机试题1、输入一个字符串,判断判断这个字符串是否对称例如abcba算对称abccba也算对称packagecom.wz.test01;importjava.util.Scanner;publicclasstest01{/***输入一个字符串,判断判断这个字符串是否对称*例如abcba算对称abccba也算对称*/......
  • nacos源码分析
    下载Nacos源码访问GitHub官网地址:https://github.com/alibaba/nacos找到其release页面:https://github.com/alibaba/nacos/tags,找到其中的1.4.2.版本:点击进入后,下载Sourcecode(zip):导入Demo工程这里不做演示,可以自己建一个:结构说明:cloud-source-demo:项目父目录cloud-......
  • 底层开发代码规范
    前言:此文主要针对stm32系列工程,规范代码可以加速开发速度和dbg速度源文件和头文件格式规范 这里给出比较规范的源文件和头文件应该大致具备的一些格式。/*Includes---------------------------------------------------------------------*/#include<name.h>/*Privatet......
  • c#轻量级高并发物联网服务器接收程序源码(仅仅是接收硬件数据程序,没有web端
    c#轻量级高并发物联网服务器接收程序源码(仅仅是接收硬件数据程序,没有web端,不是java,协议自己写,如果问及这些问题统统不回复。),对接几万个设备没问题,数据库采用ef6+sqlite,可改ef+MySQL.该程序只是源码使用示例,里面有使用方法,自己研究,难度属中上层不建议新手拿原创文章,转载请说明出处......
  • C#基于海康视觉VM4.1的二次开发框架源码,有多流程框架 运动控制卡 服务框架 需要有海康
    C#基于海康视觉VM4.1的二次开发框架源码,有多流程框架运动控制卡服务框架需要有海康VM的基础并且有海康威视VM开发狗原创文章,转载请说明出处,资料来源:http://imgcs.cn/5c/668913688222.html......
  • 【.NET源码解读】深入剖析中间件的设计与实现
    .NET本身就是一个基于中间件(middleware)的框架,它通过一系列的中间件组件来处理HTTP请求和响应。在之前的文章《.NET源码解读kestrel服务器及创建HttpContext对象流程》中,已经通过源码介绍了如何将HTTP数据包转换为.NET的HttpContext对象。接下来,让我们深入了解一下.NET是如何设计中......
  • 2023最新Telegram电报群管理机器人源码+教程
    #功能##欢迎消息-当有新人进群的时候,发送欢迎消息-欢迎消息支持30秒自毁-支持设置欢迎消息的内容包含群描述和置顶消息-支持自定义欢迎消息-自定义欢迎消息支持使用变量,可以嵌入新成员的名字,群描述,置顶内容和链接等-欢迎消息可以在设置中关闭,30秒自毁功能也可以关闭##进......