HashMap的遍历方式及底层原理

news2024/11/26 18:27:04

目录

  • 概述
    • Map
    • Map的全谱系图
    • HashMap
    • key和value
  • HashMap的四种遍历方式
    • keySet
    • values
    • entrySet
    • Iterator
    • 性能分析
    • 应用场景
    • 二维表
  • 底层原理
    • key是数值型
    • key是字符类型
  • 总结:

概述

Map

    Map是Java中的一个接口,它继承自Collection接口,定义了键值对的存储和检索方法。Map中的键和值可以是任意类型的对象。常见的Map实现类有HashMap、TreeMap和LinkedHashMap等。

Map的全谱系图

在这里插入图片描述

HashMap

    HashMap是基于哈希表实现的,它提供了快速的插入和查找操作。它的存储方式是无序的,不保证键值对的顺序。

今天主要介绍HashMap

key和value

    HashMap中的key和value是键值对的组成部分。key是用于标识和查找值的对象,它必须是唯一的,且不可重复。value是与key关联的对象,它可以重复。在HashMap中,通过key来计算出存储位置并存储value,当需要获取value时,通过key来查找对应的value。HashMap中的key和value可以是任意对象,但通常会使用String、Integer等常用的类作为key和value。

HashMap的四种遍历方式

keySet

//定义一个往map里添加元素的方法
  public static Map inputMap(){
        Map<String, Integer> userMap = new HashMap<String, Integer> ();
        userMap.put("zhang1",1);
        userMap.put("zhang2",2);
        userMap.put("zhang3",3);
        userMap.put("zhang4",4);
        userMap.put("zhang5",5);
        return userMap;
    /*利用keyset进行遍历*/
    public static void showMap1(Map<String,Integer> userMap){
        for (String key:userMap.keySet()) {
            System.out.println(key+"***"+userMap.get(key));

        }
    }

values

 /*利用values进行遍历*/
    public static void showMap2(Map<String,Integer> userMap){
     
        for (Integer v:userMap.values()) {
          System.out.println(v);

        }
   
    }

entrySet

    /*利用entrySet进行遍历*/
    public static void showMap3(Map<String,Integer> userMap){
        for (Map.Entry<String,Integer> entry:userMap.entrySet()) {
            System.out.println(entry.getKey()+"==="+entry.getValue());

        }
    }

Iterator

/*利用Iterator进行遍历*/
    public static void showMap4(Map<String,Integer> userMap){
        Iterator<Map.Entry<String,Integer>> it=userMap.entrySet().iterator();
        while (it.hasNext()){
            Map.Entry<String,Integer> entry=it.next();
            System.out.println(entry.getKey()+"***"+entry.getValue());
        }
    }

性能分析

稍微修改一下inputMap代码

  public static Map inputMap(){
        Map<String, Integer> userMap = new HashMap<String, Integer> ();
        //定义一个数组,后面用来组合key用
        String str[]=new String[]{"a","b","c","d","e"};
        String key;
        Integer value;
        for (int i = 0; i < 100000; i++) {
        //定义一个随机数
            int m=(int) Math.random()*5;
            key=String.valueOf(str[m])+i*100;
            value=i;
            userMap.put(key,value);
        }
     
        return userMap;
    }

注意:给四种遍历方式分别加上开始时间和结束时间,同时把输出语句去掉,在条件一致的前提下测试性能

   /*利用values进行遍历*/
    public static void showMap2(Map<String,Integer> userMap){
        Long start=System.currentTimeMillis();
        for (Integer v:userMap.values()) {
       
        }
        Long end=System.currentTimeMillis();
        System.out.println("values="+(end-start));
    }

输出结果如图所示:

在这里插入图片描述
    Iterator和values速度最快,keyset速度最慢,当然每次运行时间会有些变化,但是keyset还是最慢,其他三个效率差不多。

应用场景

  1. EntrySet遍历方式适用于需要在遍历过程中对键值对进行操作或者获取键值对的键和值的场景。
  2. KeySet遍历方式适用于只需要获取键的场景。
  3. Values遍历方式适用于只需要获取值的场景。
  4. 当需要在遍历过程中对HashMap进行修改操作时,可以使用迭代器遍历方式。迭代器提供了安全的遍历方式,可以在遍历过程中对HashMap进行增删操作,而不会抛出ConcurrentModificationException异常。
    当需要按照特定的顺序遍历HashMap时,可以使用迭代器遍历方式。迭代器可以通过调用HashMap的sort()方法进行排序,然后按照排序后的顺序遍历HashMap。

注意:如果使用JDK 8及以上的版本,并且希望代码简洁,还可以使用Lambda表达式遍历方式。此处不作为叙述内容。

二维表

遍历方式获取键值对的键和值获取键获取值是否支持修改操作是否支持按照特定顺序遍历
EntrySet方式
KeySet方式
Values方式
迭代器方式

底层原理

我们通过测试发现

  • Hashmap是无序的(遍历输出顺序和put进去的顺序无关)
  • 但是也不是随机输出

那么put之后HashMap是如何决定键值映射所处的位置呢?

key是数值型

    public static void main(String[] args) {
        Map<Integer,String> map=new HashMap();
        map.put(120,"a");//120%16=8
        map.put(37,"a");//37%16=8
        map.put(61,"a");//61%16=8
        map.put(40,"a");//40%16=8
        map.put(92,"a");//92%16=8
        map.put(78,"a");//78%16=8
        System.out.println(map);

    }

    如代码注释所示,HashMap底层是通过位运算的方式将key转化为哈希码对16求余数(此处直接求余数)决定存储位置,其中120和40对16取余数(map在初始化的时候默认长度是16)结果都是8,产生了碰撞,也就是坐标相同,此时会产生一个链表的形式。8这个坐标指向120,120键值映射的Entry里的next指向了40。

在这里插入图片描述

附一张HashMap的Entry结构

在这里插入图片描述

输出结果和上图分析一致
在这里插入图片描述

key是字符类型

    如果key是字符类型,定位的过程与其他类型的key是相同的。HashMap内部使用哈希算法来确定key在数组中的索引位置。具体的定位过程如下:

    首先,HashMap会调用key的hashCode()方法来获取key的哈希码。hashCode()方法是Object类的方法,所有的对象都可以调用该方法来获取它们的哈希码。

    然后,HashMap会使用哈希码进行计算,通过哈希算法将key映射到数组中的一个索引位置。HashMap使用的哈希算法是将哈希码与数组的长度进行按位与操作,得到的结果就是key在数组中的索引位置。

    如果发生哈希冲突(即不同的key计算出的索引位置相同),HashMap会使用链表或红黑树来解决冲突。具体来说,如果链表长度小于8,HashMap会将新的键值对添加到链表的末尾;如果链表长度大于等于8,HashMap会将链表转换为红黑树,以提高查找效率。

在这里插入图片描述

    这里提一下红黑树(Red-Black Tree),它是一种自平衡的二叉搜索树,它在数据结构中被广泛应用。红黑树的特点是具有较好的平衡性和高效的查找、插入和删除操作。在Java中,红黑树主要用于解决HashMap中的哈希冲突。
TreeMap也使用了红黑树来实现有序映射。TreeMap是基于红黑树实现的,它根据键的自然顺序或自定义比较器的顺序对键进行排序。
总的来说红黑树是一种用于解决哈希冲突和实现有序映射的数据结构。在HashMap中,红黑树用于解决哈希冲突;而在TreeMap中,红黑树用于实现有序映射。

总结:

    HashMap的遍历方式主要有keySet、Values、ntrySet和Iterator。其中EntrySet适用于需要在遍历过程中对键值对进行操作或者获取键值对的键和值的场景。KeySet适用于只需要获取键的场景。 Values适用于只需要获取值的场景。 当需要在遍历过程中对HashMap进行修改操作时,可以使用迭代器方式。底层原理是通过遍历数组的每个元素,然后遍历链表或红黑树的每个节点来实现遍历。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/753515.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GB35114双向身份认证(A级)学习笔记

GB35114双向身份验证学习笔记 温故而知新 SSL单向认证 摘录自&#xff1a;https://blog.csdn.net/qq_45759354/article/details/128672828 SSL协议用到了对称加密和非对称加密&#xff0c;在建立连接时&#xff0c;SSL首先对对称加密密钥使用非对称加密。连接建立好后&…

Docker 安装 Nacos 单节点

Docker 安装 Nacos 单节点 1 搜索 Nacos2 下载 Nacos3 安装 Nacos Nacos&#xff08;中文名“云注册中心和配置中心”&#xff09;是一个用于动态服务发现、配置管理和服务管理的开源项目&#xff0c;它由阿里巴巴集团开发并开源。Nacos提供了一种简单而强大的方式来实现微服务…

自动化用例编写思路 (使用pytest编写一个测试脚本)

目录 一&#xff0c;明确测试对象 二&#xff0c;编写测试用例 构造请求数据 封装测试代码 断言设置 三&#xff0c;执行脚本获取测试结果 四&#xff0c;总结 经过之前的学习铺垫&#xff0c;我们尝试着利用pytest框架编写一条接口自动化测试用例&#xff0c;来厘清接口…

系统调用与函数调用有什么区别?

本文我们来聊聊系统调用与普通的函数调用之间的区别。 作为程序员你肯定写过无数的函数&#xff0c;假设有这样两个函数&#xff1a; void funcB() {} void funcA() { funcB();} 函数之间是可以相互调用的&#xff0c;这很简单很happy有没有。 要知道是代码、是函数就可以相…

ABAP 发送特定格式内容的邮件

项目中&#xff0c;经常会有需求&#xff0c;向客户&#xff0c;供应商发送邮件&#xff0c;但是会有一些格式上的要求。 我们一般使用长文本来处理此类需求 举例&#xff0c;客户需要发送一个如下邮件主体内容&#xff08;带格式&#xff09; Dear Customer, Attached is y…

相机图像质量研究(2)ISP专用平台调优介绍

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

洛谷:P5016 龙虎斗 ← NOIP2018 普及组T2

【题目来源】https://www.luogu.com.cn/problem/P5016【题目描述】 轩轩和凯凯正在玩一款叫《龙虎斗》的游戏&#xff0c;游戏的棋盘是一条线段&#xff0c;线段上有 n 个兵营&#xff08;自左至右编号 1∼n&#xff09;&#xff0c;相邻编号的兵营之间相隔 1 厘米&#xff0c;…

psutil库使用详解

一、背景 在Python的世界里&#xff0c;有一些库因其强大的功能和易用性而备受开发者们的喜爱。今天&#xff0c;我们要介绍的就是其中的一员——psutil库。psutil(python system and process utilities)是一个跨平台的第三方库&#xff0c;用于获取系统运行时的进程和系统利用…

MySQL 事务与存储引擎

目录 一、MySQL事务的概念 二、事务的ACID特点 2.1 原子性 2.2 一致性 2.3 隔离性 2.4 持久性 2.5 事务之间的相互影响 三、Mysql及事物隔离级别 3.1 查询全局事务隔离级别 3.2 查询会话事务隔离级别 3.3 设置全局事务隔离级别 3.4 设置会话事务隔离级别 …

Android自定义圆环进度条/刻度仪表盘(单环单点带动画)

效果图: 1.自定义HeartDashBoardView /*** 刻度仪表盘*/ public class HeartDashBoardView extends View {private static final float START_ANGLE 135f;private static final float MAX_ANGLE 270f;private float progress 0;private float centerX;private float center…

快快快快快快快快快快排

作者简介&#xff1a;დ旧言~&#xff0c;目前大一&#xff0c;现在学习Java&#xff0c;c&#xff0c;Python等 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 望小伙伴们点赞&#x1f44d;收藏✨加关注哟&#x1f495;&#x1f495; C语言实现快排☺️ ℹ️…

应届毕业生要如何准备秋招简历?

秋招对于应届毕业生是一个求职的重要渠道&#xff0c;但是很多应届毕业生却不知道要如何制作秋招简历。那么&#xff0c;秋招简历应该如何制作呢&#xff1f;接下来&#xff0c;小编给大家讲一讲简历制作&#xff08;https://www.jiaobu365.com/&#xff09;的哪些事&#xff0…

2023 世界人工智能大会(WAIC)人才培养论坛成功举办!

Datawhale论坛 来源&#xff1a;2023 世界人工智能大会&#xff08;WAIC&#xff09; 前 言 2023 年 7 月 8 日&#xff0c;“2023世界人工智能大会”&#xff08;WAIC&#xff09;落下帷幕。7 月 8 日上午&#xff0c;WAIC 的主要分论坛之一“AIGC时代下的青年开发者人才培养…

什么样的性能测试工具才算是好的工具呢?

一、性能测试工具的特征 调度能力 因为性能测试不可能由一台压力机完成或者说大部分情况下&#xff0c;我们不能不可能由一台压力机来完成&#xff0c;凡是对压力真正有所要求的场景&#xff0c;往往是多台压力机共同施加压力完成性能测试&#xff1b;因此&#xff0c;性能测…

【GitHub】强大的终端录制工具-Terminalizer

Terminalizer 是一个GitHub上优秀的开源项目&#xff0c;目前项目点赞数已达&#xff1a;14k&#xff0c;该项目可以轻松记录下你在命令行的操作&#xff0c;并将录制好的内容输出成 gif 图像或直接分享到网上。 项目开源协议&#xff1a;MIT 项目主开发语言&#xff1a;JavaSc…

Vue计算属性:简化数据处理和视图更新的利器

一、计算属性的基本使用 计算属性&#xff1a;一个特殊属性&#xff0c;值依赖于另外一些数据动态计算出来。&#x1f6a9;&#x1f6a9;&#x1f6a9;计算属性特点&#xff1a;函数内使用的变量改变&#xff0c;重新计算结果返回。&#x1f4a3;&#x1f4a3;&#x1f4a3;注…

uniapp实现聊天消息触,vue3和vue2实现聊天消息触底 scrollTop ,scrollHeight Pc端H5端都适用

uniapp触底SDN链接如下(本人的另一篇博客) uniapp聊天时时触底链接 Pc端 模拟手机端H5 vue3写法 <template><div><!-- 聊天窗体 --><div class"test" id"gundong"><div class"text" v-for"p in chat"&…

Html基础知识学习——兼容问题与解决方法

文章目录 1.计算一定要精确&#xff0c;不要让内容的宽高超出我们设置的宽高&#xff0c;在IE6下内容会撑开设置好的宽高2.元素浮动&#xff0c;宽度需要内容撑开&#xff0c;就给里面的块元素都加浮动3.在ie6.ie7下元素要浮动并在同一行 就给这些元素都加浮动4.注意标签嵌套规…