Java集合--Map

1、Map集合概述

   在Java的集合框架中,Map为双列集合,在Map中的元素是成对以<K,V>键值对的形式存在的,通过键可以找对所对应的值。Map接口有许多的实现类,各自都具有不同的性能和用途。常用的Map接口实现类有HashMapHashtableTreeMapLinkedHashMapConcurrentHashMap

2、Map集合主要特点

  • Map中的元素都是以<K,V>键值对的形式存在;
  • Map中每个键最多映射到一个值,也就是说通过一个key最多只能获取到一个值;
  • Map中的key是无序的、不可重复的;
  • Map中的value是无序的、可重复的;

3、HashMap

3.1、HashMap简介

   HashMap 是 Java 中一个非常常用的集合类,可以通过key的 HashCode 值来快速访问值,具有很快的访问速度,并且由于存储的键值对是无序的,插入的顺序并不会影响到查询的结果。
   在 HashMap 中,允许存储的键为 null,value也可以为null,但只能有一个key 为 null。键值对是通过键的 HashCode 值来存储的,如果多个键的 HashCode 值相同,它们就会被存储在同一个桶中,也就是所谓的哈希桶。每个桶是一个单向链表或双向链表,存储了所有哈希值相同的键值对。当我们向 HashMap 中添加一个键值对时,它会根据键的 HashCode 值计算出一个哈希桶的索引,然后将键值对存储在对应的哈希桶中,并将哈希桶中的链表或双向链表更新为当前节点后面的节点。
   HashMap 继承自 AbstractMap,实现了 Map、Cloneable、java.io.Serializable 接口。HashMap 的 key 与 value 类型可以相同也可以不同,可以是字符串(String)类型的 key 和 value,也可以是整型(Integer)的 key 和字符串(String)类型的 value。

3.2、HashMap底层数据结构

Java 中的 HashMap 底层数据结构主要由数组链表红黑树三部分组成,jdk 1.8之前采用数组+链表,jdk 1.8 采用数组+链表+红黑树的方式。
在这里插入图片描述

  1. 数组(Array):HashMap 内部维护了一个 Entry 数组,用于存储键值对。每个 Entry 包含了一个键对象和一个值对象,它们都是通过哈希函数计算得到的哈希码值作为索引,存放在数组中。
  2. 链表(Linked List):当多个键的哈希码值相同时,它们会被存储在同一个桶中,也就是所谓的哈希桶。每个桶是一个单向链表或双向链表,存储了所有哈希值相同的键值对,链表是为了解决hash冲突的。
  3. 红黑树(Tree):当链表的长度超过阈值时,在JDK 1.8 之后这个阈值默认为 8,链表会转换成红黑树。红黑树是一种自平衡的二叉查找树,可以快速查找元素。
3.3、HashMap常见问题
3.3.1、哈希码是什么?

   哈希码(Hash Code)是用于计算键的哈希值,以便在存储和查询时使用的。哈希码的计算方式是通过将键的哈希值存储在数组中的一个位置上,这个位置称为哈希码值。当我们向 HashMap 中添加键值对时,HashMap 会使用键的哈希值来计算哈希码值,并将键值对存储在对应的哈希码值的位置上。当我们查询 HashMap 中的键值对时,HashMap 会使用键的哈希码值来计算哈希码值的位置,并在该位置上遍历所有的键值对,直到找到对应的键值对。

3.3.2、为什么哈希码在HashMap中很重要?

   哈希码的重要性在于,它可以帮助我们快速地定位键值对在数组中的位置,从而提高 HashMap 的存储和查询效率。如果两个键的哈希码不同,它们会被分配到不同的桶中;如果哈希码相同,就会发生哈希冲突,需要进一步处理。

3.3.3、HashMap中如何处理哈希冲突?

   为了解决哈希冲突,HashMap 使用了链地址法,即将哈希桶转换成一个链表或红黑树,存储所有哈希值相同的键值对。当多个键的哈希码值相同时,HashMap 会将它们存储在同一个桶中,并将它们转换成链表或红黑树的形式。当我们查询键值对时,HashMap 会遍历该桶中的所有键值对,直到找到对应的键值对。如果该桶中没有对应的键值对,则说明该键值对不存在,HashMap 会返回 null。

3.3.4、为什么HashMap不是线程安全的?

   HashMap 内部使用了数组和链表(或红黑树)来存储键值对,当多个线程同时访问 HashMap 时,可能会出现以下问题:

  1. 多线程修改元素出现的不安全:线程 A 和线程 B 同时修改同一个 HashMap 中的键值对,由于 HashMap 是线程不安全的,当线程 A 修改键值对时,线程 B 也可能在同时修改键值对,导致数据不一致或丢失。
  2. 多线程并发扩容出现的不安全:HashMap在达到阈值时需要进行扩容,扩容时需要重新计算Hash值,重新分配存储位置。如果在扩容过程中有多个线程同时进行插入或删除操作,就可能会导致数据结构混乱,还可能会导致Map中链表的尾结点指向头结点造成死循环。
3.3.5、HashMap初始化容量是多少?

  在创建 HashMap 对象时,需要传入一个整数参数,表示 HashMap 中桶的数量,默认情况下,该参数为 16。初始化容量的大小会直接影响到 HashMap 的空间利用率和性能。如果初始化容量太小,可能会导致频繁的扩容操作,从而降低性能;如果初始化容量太大,则会导致空间浪费,并且当需要进行扩容时,需要重新计算数组大小,并重新分配内存等,也会消耗一定的系统资源。

3.3.6、HashMap 为什么需要动态扩容?

  为了提高 HashMap 的查询效率。当桶中链表或红黑树的长度超过一定阈值时,该阈值默认为初始容量的两倍加上负载因子的值,即 2 * initialCapacity + 0.5f。超过这个阈值会自动进行扩容到之前容量的2倍,阈值也为原来的2倍。扩容时,HashMap 会重新分配一个新的桶数组,并将原来的键值对数据复制到新的桶数组中。新的桶数组的大小通常是原来的两倍,以便容纳更多的键值对数据。由于 HashMap 的扩容操作需要重新计算哈希值,因此在扩容时会导致性能下降。为了尽可能减少扩容带来的性能损失,建议在创建 HashMap 实例时,根据实际需要设置合适的容量大小。

3.3.7、HashMap的加载因子是什么?

  在 Java 中的 HashMap 中,加载因子是一个重要的参数,它决定了 HashMap 在初始化时所分配的桶的数量。加载因子的取值范围是 0.75 到 1.0 之间,通常情况下,默认的加载因子是 0.75。
  加载因子的作用是控制 HashMap 中桶的数量,当桶的数量达到了加载因子所指定的最大值时,就需要进行扩容操作。加载因子的取值会直接影响到 HashMap 的空间利用率和性能,如果加载因子的取值过小,则会导致频繁的扩容操作,从而降低性能;如果加载因子的取值过大,则会导致空间浪费,并且当需要进行扩容时,需要重新计算数组大小,并重新分配内存等,也会消耗一定的系统资源。

3.3.8、HashMap如何保证key的唯一性?

  当存储键值对时,先对key的hashCode值进行比较,如果不同,则认为两个key不相等,会直接插入集合中。如果两个key的hashCode值相同,则会调用equals()方法进行比较,如果equals()方法返回true,则认为两个key相等,则会覆盖掉原来的键值对;否则认为两个key不相等,会两个key会放入到同一个哈希桶中。

3.3.9、HashMap中为什么重写equals方法要重写hashcode方法?

  在 Java 中,HashMap 类使用键的哈希值和键对象的equals方法来实现键的唯一性。equals方法用于比较两个对象是否相等,而hashCode方法用于生成键对象的哈希码。当两个对象通过equals方法比较相等时,它们的hashCode方法应该返回相同的值。如果两个对象的equals()方法返回true,但是它们的hashCode()方法返回的哈希码不同,那么它们就会被存在HashMap的不同桶里,导致HashMap无法正确获取对象。

3.3.10、HashMap一般用什么作为key?

  在 Java 中的 HashMap 类中,键可以是任何实现了 Comparable 接口的对象。最常用的键类型是字符串。这是因为字符串类型的键可以方便地进行比较和排序,并且可以轻松地进行字符串转换。另外,字符串类型的键还可以方便地进行序列化和反序列化操作,从而方便进行数据传输和存储。其他比较常用的类型如:Integer、Long、String、Object等都可以作为key。

4、Hashtable

4.1、Hashtable 简介

  Hashtable 是 Java 中的一个同步的键值对存储容器,它实现了 Map 接口。与 HashMap 不同,Hashtable 是线程安全的,它使用 synchronized 关键字将整张散列表加锁的方式来保证多线程访问时的线程安全性,因此它的运行效率非常低。
  Hashtable 的key和value都不能为 null,否则会抛出NullPointerException。

4.2、Hashtable 数据结构组成

HashTable 内部的数据结构主要包括以下几个部分:

  1. 桶数组:使用一个数组来存储键值对,这个数组长度由初始容量和负载因子决定。当有新的键值对插入时,会通过哈希算法计算出键的索引位置,然后将键值对存储在相应的桶中。
  2. synchronized 块:由于 HashTable 是线程安全的,因此在多线程环境下使用时需要进行同步操作,以防止不同线程对 HashTable 进行修改操作时发生冲突。为了保证同步操作的有效性,HashTable 使用了 synchronized 块来进行同步控制。
  3. 链表/红黑树:当 HashTable 中有多个键值对的哈希值相同时,这些键值对会被存储在同一个桶中,形成一个链表或红黑树。当链表的节点数量超过一定阈值时,会将链表转化为红黑树,以提高查找效率。
4.3、Hashtable 底层原理
  1. 初始大小为11,加载因子为0.75;
    在这里插入图片描述
  2. 阈值threshold = initialCapacity * loadFactor;
    在这里插入图片描述
  3. 扩容机制为大于阈值threshold就进行扩容;
    在这里插入图片描述

5、TreeMap

5.1、TreeMap简介

  TreeMap 是 Java 中的一个基于红黑树的排序 Map 实现,它实现了 NavigableMap 接口,用于存储有序的键值对。由于红黑树的查找效率比链表要慢一些,因此在键值对数量较多的情况下,使用 TreeMap 可能会影响性能。但是,由于 TreeMap 可以保证键值对的有序性,因此在一些需要按照键进行排序的场景下,使用 TreeMap 是比较合适的。
  TreeMap的key不能为 null,value可以为null。

5.2、TreeMap 数据结构组成

TreeMap 内部的数据结构主要包括以下几个部分:

  1. 红黑树:使用红黑树来实现有序的键值对存储,红黑树是一种自平衡的二叉搜索树,可以保证节点之间的排序关系。
  2. 排序规则:内部维护了一个比较器,用于定义键的排序规则。当插入键值对时,TreeMap 会根据比较器的返回值来确定键的排序顺序。
  3. 导航操作:提供了一些导航操作,如 subMap、navigate、climbUp、climbDown 等,用于查找、遍历、上翻、下翻等操作。

6、LinkedHashMap

6.1、LinkedHashMap简介

  LinkedHashMap 是 Java 中的一个基于双向链表的 Map 实现,它实现了 Map 接口,用于存储键值对,并支持按照插入顺序和访问顺序进行访问。由于 LinkedHashMap 是基于双向链表实现的,因此它的插入、删除、查找等操作的时间复杂度都是 O(1),性能比较优秀。但是,由于双向链表的数据结构比较简单,因此 LinkedHashMap 的可扩展性比一些基于哈希表实现的集合要好。LinkedHashMap 不支持并发访问,如果需要在多线程环境下使用,需要进行同步控制。
  LinkedHashMap 的key可以为 null,value可以为null。

6.2、LinkedHashMap 数据结构组成

LinkedHashMap 内部的数据结构主要包括以下几个部分:

  1. 双向链表:使用双向链表来存储键值对,每个节点包含前一个节点和后一个节点以及对应的键值对。
  2. 迭代器:提供了一个迭代器,用于遍历链表中的所有键值对。当迭代器遍历时,会按照插入的顺序来遍历链表。
  3. 访问顺序: 能够记录键值对的访问顺序,当访问键值对时,LinkedHashMap 会根据访问顺序来返回对应的键值对,从而实现有序的访问。

7、ConcurrentHashMap

7.1、ConcurrentHashMap简介

  ConcurrentHashMap 是 Java 中常用的一种并发安全的Map实现,它实现了 Map 接口,内部和 HashMap 一样,都是采用了数组 + 链表 + 红黑树的方式来实现。与hashtable不同,该类不依赖于synchronization去保证线程操作的安全,而是利用分段锁(CAS 锁)来保证数据的安全,支持的并发量相对更高。ConcurrentHashMap 插入、删除、查找等操作的时间复杂度都是 O(1),性能也是比较优秀。但是,由于哈希表的数据结构比较复杂,因此 ConcurrentHashMap 的可扩展性相对一些基于链表的实现集合要差。
  ConcurrentHashMap 的key和value都不可以为null。

7.2、ConcurrentHashMap 数据结构组成

ConcurrentHashMap 内部的数据结构主要包括以下几个部分:

  1. 桶(HashTable):使用桶来存储键值对,桶是一个哈希表,每个桶都包含若干个链表,用于存储键值对。
  2. 缓存区(Segment):使用缓存区来管理桶,缓存区是一个分段的数组,每个缓存区都包含若干个桶,用于提高并发访问时的性能。
  3. 分段锁(CAS 锁):使用 CAS 锁来实现并发访问,CAS 锁是一种无锁,不需要占用额外的 CPU 资源,可以提高并发访问时的性能。
7.3、ConcurrentHashMap 主要特点
  1. 并发安全:支持并发访问,能够保证线程安全,即使在多线程环境下也能够正确地访问键值对。
  2. 高性能:使用缓存区来管理桶,能够提高并发访问时的性能,同时使用 CAS 锁来实现并发访问,能够避免锁竞争,提高并发访问时的性能。
  3. 可定制的大小:支持可定制的大小,可以根据实际需要来调整大小,从而达到最佳的性能和空间利用率。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

交易历史记录20231206 记录

昨日回顾&#xff1a; select top 10000 * from dbo.CODEINFO A left join dbo.全部&#xff21;股20231206010101 B ON A.CODE B.代码 left join dbo.全部&#xff21;股20231206CONF D on A.CODED.代码left join dbo.全部&#xff21;股20231206 G on A.CODEG.代码 left…

铭飞CMS list 接口 SQL注入漏洞复现

0x01 产品简介 铭飞CMS是一款基于java开发的一套轻量级开源内容管理系统,铭飞CMS简洁、安全、开源、免费,可运行在Linux、Windows、MacOSX、Solaris等各种平台上,专注为公司企业、个人站长快速建站提供解决方案 0x02 漏洞概述 铭飞CMS在5.2.10版本以前list 接口处存在sql注入…

电子元器件介绍——电阻(一)

电子元器件 文章目录 电子元器件前言1.1电阻基本知识1.2电阻的作用1.3电阻的分类1.4 贴片电阻贴片电阻的规范、尺寸、封装 1.5 技术参数噪声&#xff1a; 1.6 电阻的失效 总结 前言 接下来我们就把常用的电子元器件全部介绍给大家&#xff0c;这一节是电阻&#xff0c;电容电感…

用提问的方式来学习:冯·诺伊曼体系结构与操作系统OS

学习冯诺伊曼体系结构之前&#xff0c;我们要本着两个问题来学习&#xff1a; 什么是冯诺伊曼体系结构&#xff1f;为什么要有冯诺伊曼体系结构&#xff1f; 一、冯诺伊曼体系结构 1. 什么是冯诺伊曼体系结构&#xff1f; 那我们就先来回答一下什么是冯诺伊曼体系结构&#x…

探索GameFi:区块链与游戏的未来融合

在过去的几年里&#xff0c;区块链技术逐渐渗透到各个领域&#xff0c;为不同行业带来了前所未有的变革。其中&#xff0c;游戏行业成为了一个引人注目的焦点&#xff0c;而这种结合被称为GameFi&#xff0c;即游戏金融。GameFi不仅仅是一个概念&#xff0c;更是一场区块链和游…

3-分布式存储之Ceph

任务背景 虽然使用了分布式的glusterfs存储, 但是对于爆炸式的数据增长仍然感觉力不从心。对于大数据与云计算等技术的成熟, 存储也需要跟上步伐. 所以这次我们选用对象存储. 任务要求 1, 搭建ceph集群 2, 实现对象存储的应用 任务拆解 1, 了解ceph 2, 搭建ceph集群 3, 了…

批量生成标题文章:AI文章创作助力高效办公,提升办公效率

随着人工智能技术的不断发展&#xff0c;AI文章创作已经成为了高效办公的新趋势。这种技术可以快速生成高质量的文章&#xff0c;从而大大提高办公效率。相比传统的手写文章&#xff0c;AI文章创作具有更高的效率和准确性。在撰写文章时&#xff0c;往往要花费大量的时间和精力…

【Jmeter】Jmeter基础8-Jmeter元件介绍之断言

断言主要用于对服务器响应的数据做验证。Jmeter提供了多个断言元件&#xff0c;其中最常用的是响应断言。 2.8.1、响应断言 作用&#xff1a;对Jmeter取样器返回值进行断言。参数说明&#xff1a; 测试字段 响应文本&#xff1a;从服务器返回的响应文本&#xff0c;Response B…

手写进度条,鼠标移入显示悬浮框

效果 <template><div class"box"><div class"mid-box"><div class"mid-contant"><!-- 提示框 --><divv-if"hover"class"tooltip":style"{top: hovertop,}"><div>{{ ho…

模块二——滑动窗口:438.找到字符串中所有字母异位词

文章目录 题目描述算法原理滑动窗口哈希表 代码实现 题目描述 题目链接&#xff1a;438.找到字符串中所有字母异位词 算法原理 滑动窗口哈希表 因为字符串p的异位词的⻓度⼀定与字符串p 的⻓度相同&#xff0c;所以我们可以在字符串s 中构造⼀个⻓度为与字符串p的⻓度相同…

基础算法(2):排序(2):计数排序

1.计数排序实现 计数排序是一个非基于比较的稳定的线性时间的排序算法&#xff0c;而选择排序是基于比较的&#xff0c;计数排序不用&#xff0c;它的实现依靠计数。 工作原理&#xff1a;使用一个额外的数组&#xff0c;其中第i个位置是待排序数组1中值等于i的元素的个数&…

Ansible介绍与安装

Ansible目前是运维自动化工具中最简单、容易上手的一款优秀软件&#xff0c;能够用来管理各种资源。用户可以使用Ansible自动部署应用程序&#xff0c;以此实现IT基础架构的全面部署。例如&#xff0c;借助于Ansible&#xff0c;我们可以轻松地对服务器进行初始化配置、安全基线…

显示器件是什么

显示器件 电子元器件百科 文章目录 显示器件前言一、显示器件是什么二、显示器件的类别三、显示器件的应用实例四、显示器件的作用原理总结前言 显示器件根据不同的技术原理和应用领域,具有不同的特点和优势,可适用于电子产品、电视、计算机显示器、手持设备、汽车仪表盘等…

产品入门第四讲:Axure动态面板

&#x1f4da;&#x1f4da; &#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; ​​​​​ &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Axure》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还…

Java刷题篇——合并两个有序数组

1.题目描述 给出一个有序的整数数组A 和有序的整数数组 B&#xff0c;请将数组B合并到数组A中&#xff0c;变成一个有序的升序数组。 数据范围&#xff1a;0 < n,m < 100, |A~i~| < 100, |B~i~| < 100 注意&#xff1a; 保证 A 数组有足够的空间存放 B 数组的元…

(C++)只出现一次的数字I--异或

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://le…

AI:100-基于卷积神经网络的农作物生长状态监测

🚀 本文选自专栏:人工智能领域200例教程专栏 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的核心代码,详细讲解供大家学习,希望可以帮到大家。欢迎订阅支持,正在不断更新…

Axure的动态面板

目录 动态面板 什么是Auxre动态模板 动态模板的步骤 应用场景 实战案例 轮播图 多功能登录界面 主界面左侧菜单栏 动态面板 什么是Auxre动态模板 动态面板是Axure中的一个重要功能&#xff0c;它允许用户创建可交互的页面&#xff0c;并模拟用户与页面的交互。通过添加元素…

智能指针管理“newed对象”

为什么要有智能指针&#xff1f; 指针智能是管理管理动态内存分配对象的一种机制。它提供了自动管理内存&#xff0c;避免常见内存泄漏和悬空指针。 对于上述Func函数的操作&#xff0c;一不小心就会产生很多问题。 p1 new时候抛异常 什么都不做p2 new时候抛异常 p1需要被清理…

Apache DolphinScheduler 社区荣获 “2023 年度优秀开源技术团队“ 奖项

在开源社区日益繁荣的今天&#xff0c;我们非常荣幸地宣布&#xff1a;Apache DolphinScheduler 社区在 OSCHINA 平台的评选中荣获了“2023 年度优秀开源技术团队”奖项。这一奖项反映了我们社区在过去一年里在内容发表的深度与广度、活动运营影响力以及对开源文化的推广方面所…