Java中Map接口的学习

news/2024/9/24 12:07:44/文章来源:https://www.cnblogs.com/BingBing-8888/p/18428882

Map接口


目录
  • Map接口
    • HashMap(掌握)
    • TreeMap(掌握)
    • LinkedHashMap
    • ConcurrentHashMap
    • identityHashMap
    • HashTable(过时)

HashMap(掌握)

Java中的HashMap是一种基于哈希表实现的Map接口的非同步集合,它提供了快速的查找、插入和删除操作。以下是HashMap的特点、底层数据结构以及常用方法的详细解析:

特点

  1. 键值对存储:HashMap存储的是键值对(Key-Value Pair),其中键是唯一的,而值可以重复。

  2. 非线程安全:HashMap不是线程安全的,如果多个线程同时访问HashMap,可能会导致数据不一致的情况。如果需要线程安全的Map,可以考虑使用ConcurrentHashMap。

  3. 允许null键和null值:HashMap允许键和值都为null,但每个键只能映射到最多一个值。

  4. 遍历无序:HashMap中的数据是无序的,遍历时不能保证元素的顺序。

  5. 高效性能:在大多数情况下,HashMap的插入和查找操作的时间复杂度都是O(1),这得益于其哈希表的数据结构。

  6. 初始容量和加载因子:可以通过构造方法指定HashMap的初始容量和加载因子,以优化其性能。初始容量是哈希表在创建时的容量,加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。

  7. 支持泛型:HashMap支持泛型,可以指定键和值的类型,提高代码的安全性和可读性。

  8. key的唯一性:HashMap中的key是唯一的,如果插入重复的key,则会覆盖原有的value。

底层数据结构

HashMap的底层数据结构是数组和链表(或红黑树)的组合,这种数据结构被称为哈希表(Hash Table)。在HashMap中,数据是以键值对的形式存储的,每个键值对被封装成一个Entry对象,其中包含了键和值。

  • 数组:HashMap底层实际上是一个一维数组,数组的每个元素是一个单向链表(或红黑树)的头节点。
  • 链表或红黑树:当两个键的哈希值相同时,它们会被放置在同一个数组位置上,形成一个链表(或红黑树)。在JDK 1.8及以后的版本中,当链表长度超过8时,链表会转换为红黑树以提高查找效率;当链表长度小于6时,红黑树会转换回链表以节省空间。

常用方法

HashMap提供了多种常用方法来支持其操作,包括但不限于:

  1. put(K key, V value):将指定的键与值映射存放到Map集合中。如果键已存在,则更新其值。

  2. get(Object key):返回指定键所映射的值,如果键不存在,则返回null。

  3. size():返回Map集合中数据数量。

  4. clear():清空Map集合中的所有元素。

  5. isEmpty():判断Map集合中是否有数据,如果没有则返回true,否则返回false。

  6. remove(Object key):删除Map集合中键为key的数据,并返回其所对应的value值。

  7. values():返回Map集合中所有value组成的Collection集合。

  8. containsKey(Object key):判断集合中是否包含指定键,包含返回true,否则返回false。

  9. containsValue(Object value):判断集合中是否包含指定值,包含返回true,否则返回false。

  10. keySet():返回Map集合中所有key组成的Set集合。

  11. entrySet():将Map集合每个key-value转换为一个Entry对象并返回由所有的Entry对象组成的Set集合。

HashMap的这些特点、底层数据结构以及常用方法使得它在Java开发中有着广泛的应用,特别是在需要快速查找、插入和删除操作的场景中。

TreeMap(掌握)

Java中的TreeMap是一种实现了Map接口和SortedMap接口的有序映射表,

特点

  1. 有序性TreeMap通过其键的自然顺序或者通过创建时提供的Comparator进行排序,保证了映射的顺序性。
  2. 唯一性TreeMap中的键是唯一的,不允许存在重复的键,但值可以重复。
  3. 非线程安全TreeMap不是线程安全的,如果在多线程环境下使用,需要进行适当的同步控制。
  4. 高效性TreeMap的底层基于红黑树实现,确保了插入、删除和查找操作的高效性,这些操作的时间复杂度通常为O(log n),其中n是映射中键值对的数量。
  5. 内存占用:由于内部采用红黑树数据结构,TreeMap的内存占用相对较高,比HashMap稍微大一些。

底层数据结构

TreeMap的底层数据结构是红黑树(Red-Black Tree),这是一种自平衡的二叉查找树。红黑树通过特定的性质(如节点是红色或黑色、每个叶子节点(NIL节点,空节点)是黑色的、每个红色节点的两个子节点都是黑色的、从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点)来维护树的平衡,从而保证了高效的查找、插入和删除操作。

常用方法

TreeMap提供了多种常用方法,包括但不限于:

  1. put(K key, V value):向映射中添加一个键值对。如果映射以前包含该键的映射关系,则替换旧值(可选操作)。
  2. get(Object key):返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回null
  3. remove(Object key):如果存在一个键的映射关系,则将其从映射中移除(可选操作)。
  4. containsKey(Object key):如果此映射包含指定键的映射关系,则返回true
  5. isEmpty():如果此映射不包含任何键-值映射,则返回true
  6. size():返回此映射中的键值对数量。
  7. clear():从此映射中移除所有映射关系(可选操作)。
  8. firstKey():返回此映射中当前第一个(最低)键。
  9. lastKey():返回此映射中当前最后一个(最高)键。
  10. keySet():返回此映射中包含的键的Set视图。
  11. values():返回此映射中包含的值的Collection视图。
  12. entrySet():返回此映射中包含的映射的Set视图。

需要注意的是,在使用TreeMap时,如果键没有实现Comparable接口且没有提供Comparator,则会在运行时抛出ClassCastException。此外,TreeMap不允许键为null,但可以在自定义排序的情况下允许值为null(具体取决于Comparator的实现)。

总的来说,TreeMap在需要保持键值对映射顺序的场景下非常有用,它通过红黑树数据结构实现了高效的键值对存储、添加、删除和查找操作。

LinkedHashMap

Java中的LinkedHashMap是一种特殊的Map实现,它在HashMap的基础上增加了一个双向链表,以保持键值对的插入顺序或访问顺序。

特点

  1. 有序性LinkedHashMap可以保持键值对的插入顺序或访问顺序,这取决于构造方法中的accessOrder参数。

    • accessOrderfalse时(默认值),迭代顺序与插入顺序一致。
    • accessOrdertrue时,迭代顺序为访问顺序,即最近访问的元素会被移动到链表的尾部,最近最少访问的元素会排在链表的前面。
  2. 性能:尽管LinkedHashMap在插入和删除元素时由于需要维护双向链表而略慢于HashMap,但在迭代访问时,随着元素个数的增加,其迭代效率会比HashMap高很多,因为可以利用链表结构快速遍历。

  3. 非线程安全LinkedHashMap不是线程安全的,如果需要在多线程环境下使用,需要进行适当的同步控制或使用Collections.synchronizedMap进行封装。

  4. 允许null键和null值:与HashMap相同,LinkedHashMap也允许键和值都为null,但每个键只能映射到最多一个值。

底层数据结构

LinkedHashMap的底层数据结构是由一个哈希表(基于数组和链表/红黑树)和一个双向链表组成。

  • 哈希表:用于存储键值对,其结构与HashMap相同,通过哈希码和数组索引快速定位到具体的桶(bucket),桶内可能是一个链表或红黑树,用于解决哈希冲突。
  • 双向链表:每个节点除了存储键值对外,还包含指向前驱节点和后继节点的指针,用于维护元素的插入顺序或访问顺序。

常用方法

LinkedHashMap继承了HashMap的所有方法,并提供了以下常用方法(部分方法已在HashMap中介绍,但在此列出以强调其在LinkedHashMap中的适用性):

  1. 构造方法

    • LinkedHashMap():创建一个默认容量和负载因子的空LinkedHashMap
    • LinkedHashMap(int initialCapacity):创建一个指定初始容量和默认负载因子的空LinkedHashMap
    • LinkedHashMap(int initialCapacity, float loadFactor):创建一个指定初始容量和负载因子的空LinkedHashMap
    • LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder):创建一个指定初始容量、负载因子和访问顺序的空LinkedHashMap
    • LinkedHashMap(Map<? extends K, ? extends V> m):创建一个包含给定Map元素的LinkedHashMap,插入顺序为给定Map元素的顺序。
  2. 增删改查

    • put(K key, V value):向LinkedHashMap中插入键值对。
    • get(Object key):获取指定键对应的值。如果accessOrdertrue,则在访问节点后,会将其移动到链表的尾部。
    • remove(Object key):从LinkedHashMap中删除指定键值对。
    • clear():清空LinkedHashMap中的所有键值对。
  3. 判断与获取

    • containsKey(Object key):判断LinkedHashMap中是否包含指定的键。
    • containsValue(Object value):判断LinkedHashMap中是否包含指定的值。
    • size():返回LinkedHashMap中键值对的个数。
    • isEmpty():判断LinkedHashMap是否为空。
  4. 视图方法

    • keySet():返回LinkedHashMap中所有键的Set视图。
    • values():返回LinkedHashMap中所有值的Collection视图。
    • entrySet():返回LinkedHashMap中所有键值对的Set视图。

ConcurrentHashMap

Java中的ConcurrentHashMap是一个高效且线程安全的哈希表实现,它在多线程环境下提供了比Hashtable更高的并发性能。

特点

  1. 高性能ConcurrentHashMap采用了分段锁(在JDK 1.7及之前版本)或CAS(Compare-And-Swap)和synchronized关键字(在JDK 1.8及之后版本)等机制,实现了高效的并发访问,使得多线程环境下的读写操作更加高效。

  2. 线程安全ConcurrentHashMap是线程安全的,允许多个线程同时读写数据,而无需外部同步。它通过内部锁机制或CAS操作来保证数据的一致性和线程安全性。

  3. 分段锁/锁分离:在JDK 1.7及之前版本中,ConcurrentHashMap通过将哈希表分成多个段(Segment),每个段都有独立的锁,从而实现了锁分离。这样,不同的线程可以同时访问不同的段,提高了并发性能。而在JDK 1.8及之后版本中,虽然不再显式地使用分段锁,但每个Node(或桶)的更新操作仍然是线程安全的,通过CAS和synchronized关键字来保证。

  4. 弱一致性ConcurrentHashMap提供了弱一致性的原则,即当一个线程进行写入后,不保证其他线程立即可见修改结果。这种设计是为了提供更好的吞吐量和减少同步开销。

  5. 不支持空键值对ConcurrentHashMap不允许键(key)和值(value)为null,如果尝试插入null键值对,会抛出NullPointerException异常。

  6. 动态扩容:当哈希表中的元素数量超过负载因子与当前容量的乘积时,ConcurrentHashMap会自动进行扩容,以维护良好的性能。

底层数据结构

  • JDK 1.7及之前版本:底层采用分段锁(Segment)机制,每个Segment内部是一个类似于HashMap的结构,包含一个哈希表(数组+链表)。
  • JDK 1.8及之后版本:底层采用Node数组+链表/红黑树的结构。当链表长度超过一定阈值时,会自动转换为红黑树,以提高查询效率。同时,使用CAS和synchronized关键字来保证线程安全。

常用方法

  1. put(K key, V value):向ConcurrentHashMap中插入键值对。如果键已存在,则更新其对应的值。

  2. get(Object key):根据键获取对应的值。如果键不存在,则返回null。

  3. remove(Object key):根据键删除键值对,并返回被删除的值。如果键不存在,则返回null。

  4. putIfAbsent(K key, V value):仅当键不存在时,才向ConcurrentHashMap中插入键值对。如果键已存在,则不进行任何操作,并返回已存在的值。

  5. computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction):如果指定的键不存在,则计算其值,并将其与键关联(或放入)到映射中,除非为null。

  6. computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction):如果指定的键存在且其值不为null,则对其值应用给定的函数,并将返回值与键关联(或放入)到映射中,替换旧值。

  7. entrySet()keySet()values():分别返回映射中包含的键值对集合、键集合和值集合的视图。

  8. forEach(BiConsumer<? super K,? super V> action):对映射中的每个键值对执行给定的操作。

综上所述,ConcurrentHashMap是Java并发编程中一个非常重要的数据结构,它通过高效的并发机制和动态扩容能力,为多线程环境下的数据操作提供了强大的支持。

identityHashMap

Java中的IdentityHashMap是一种特殊的哈希表实现,它基于对象的引用相等性(而非equals()方法)来比较键。

特点

  1. 引用相等性IdentityHashMap在比较键时,使用的是对象的引用相等性(即==操作符),而不是equals()方法。这意味着两个对象即使内容相同,但如果它们不是同一个对象的引用,那么在IdentityHashMap中将被视为不同的键。

  2. 非通用性IdentityHashMap不是通用的Map实现,它故意违反了Map接口的一般契约,即要求在比较对象时使用equals()方法。因此,它仅用于需要引用相等语义的极少数情况。

  3. 性能:在大多数情况下,IdentityHashMap的性能与HashMap相似,因为它也使用了哈希表来存储键值对。但是,由于它不需要调用对象的equals()hashCode()方法,因此在某些情况下可能会表现出更好的性能(特别是当这些方法的实现较为复杂时)。

  4. 非线程安全IdentityHashMap不是线程安全的,如果需要在多线程环境下使用,需要进行适当的同步控制。

底层数据结构

IdentityHashMap的底层数据结构是一个Object数组,用于存储键值对。但是,与HashMap不同,IdentityHashMap并没有使用链表或红黑树来解决哈希冲突。相反,它直接将键和值存储在数组中,每个键值对占据数组中的两个连续位置(一个用于键,一个用于值)。

当添加元素时,IdentityHashMap会根据键的引用哈希码计算出一个索引值,并将键值对存储在数组的相应位置。如果发生哈希冲突(即不同的键计算出了相同的索引值),则由于IdentityHashMap不使用链表或红黑树,这种情况通常不会直接出现。然而,如果数组容量不足,IdentityHashMap会进行扩容操作,以容纳更多的键值对。

常用方法

IdentityHashMap提供了与HashMap类似的常用方法,但由于其特殊的键比较方式,这些方法的行为可能会有所不同。以下是一些常用的方法:

  • put(K key, V value):将指定的键值对添加到映射中。如果映射中已经包含了该键的映射,则旧值将被替换为新值。
  • get(Object key):返回指定键所映射的值;如果此映射不包含该键的映射,则返回null
  • containsKey(Object key):如果此映射包含指定键的映射,则返回true
  • containsValue(Object value):如果此映射将一个或多个键映射到指定值,则返回true
  • remove(Object key):如果存在该键的映射,则将其从此映射中移除;返回被移除的值,如果不存在该键的映射,则返回null
  • size():返回此映射中的键值对数量。
  • isEmpty():如果此映射不包含任何键值对,则返回true

HashTable(过时)

Java中的Hashtable是一个经典的集合类,用于存储键值对。

特点

  1. 线程安全Hashtable是线程安全的,这意味着多个线程可以同时访问它而不会出现数据竞争问题。它通过方法级同步来实现线程安全,但这种同步机制也带来了一定的性能开销。

  2. 不允许null键和null值:与HashMap不同,Hashtable不允许键或值为null。如果尝试插入null键或值,将抛出NullPointerException

  3. 可序列化Hashtable实现了Serializable接口,因此可以将其序列化到流中,以便在网络中传输或保存到文件中。

  4. 容量和负载因子Hashtable有默认的初始容量(通常为11)和负载因子(通常为0.75)。当哈希表中的元素数量超过负载因子与当前容量的乘积时,哈希表会进行扩容。

  5. 旧式API:尽管Hashtable在Java集合框架中仍然可用,但它被视为一种旧式的API。在Java 2平台中引入了HashMap作为更现代、更灵活的替代品。

底层数据结构

Hashtable的底层数据结构是基于哈希表的,具体来说,它是由一个数组和一个哈希函数组成。数组中的每个元素都可以看作是一个“桶”或“存储桶”,用于存储键值对。在JDK 1.8及以后的版本中,为了处理哈希冲突(即不同的键映射到同一个索引位置),每个桶可能是一个链表或者是一个红黑树(当链表长度超过一定阈值时)。通过哈希函数,Hashtable能够将键映射到数组的索引位置,从而实现快速存取和查找。

常用方法

Hashtable提供了一系列用于操作键值对的方法,包括添加、获取、删除和检查等。以下是一些常用的方法:

  • put(K key, V value):将指定的键值对添加到哈希表中。如果哈希表中已存在具有该键的键值对,则替换其值。
  • get(Object key):返回与指定键相关联的值。如果哈希表中不包含该键的映射,则返回null
  • remove(Object key):从哈希表中移除与指定键相关联的键值对。如果哈希表包含该键的映射,则返回被移除的值;否则返回null
  • containsKey(Object key):检查哈希表中是否包含指定的键。
  • containsValue(Object value):检查哈希表中是否包含指定的值。
  • size():返回哈希表中的键值对数量。
  • isEmpty():检查哈希表是否为空。
  • keys():返回包含哈希表中所有键的Enumeration对象。注意,这个方法返回的是Enumeration接口的实现,而不是Set
  • elements():返回包含哈希表中所有值的Enumeration对象。
  • entrySet():返回包含哈希表中所有键值对的Set视图。这个Set中的每个元素都是一个Map.Entry对象,代表一个键值对。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于异或哈希

Re:异或哈希Re:疑惑异或哈希 异或哈希是个很神奇的算法,利用了异或操作的特殊性和哈希降低冲突的原理,可以用于快速找到一个组合是否出现、序列中的数是否出现了 \(k\) 次 算法如其名,异或+哈希。 想起某首歌叫PPAP? I have a \(\oplus\),I have an \(hash\). (Uhh~) \(\…

threejs 使用base64编码的图片作为贴图

使用base64作为贴图可以从接口直接传输(如果特别大需要压缩),可以省去很多操作 代码如下// 纹理加载器 const texLoader = new THREE.TextureLoader(); const base64Str = "data:image/png;base64,..."; texLoader.load(base64Str, (texture) => {const aspectR…

WPS在堆积柱状图上显示加总数据

我们常常会用到堆积柱状图,每个色块都可以显示数值,那如何在图上显示加总数据呢?今天分享一个小方法。以2024年前三周手机销量为例:首先将数据整理如下,最后一列求和。2. 选择所有数据(含合计)绘制堆积柱状图,并选中“合计”的柱状图,右键添加数据标签。3. 选择“合计”…

Vue3 注册及使用全局方法

一、背景 自己的一个考公网站,需求是 用户登录系统,但是用户去查看功能时要判断当前用户是否有是会员,如果不是会员,那么查看其他功能时需要弹窗说不是vip,如果是会员则可以直接查看。 二、实现 首先上截图。 1.Vue3 全局注册方法 1.新建popToast.jsimport Cookies from &q…

Figma UI Design add background color to text All In One

Figma UI Design add background color to text All In One 如何使用 Figma 给文字添加背景色Figma UI Design add background color to text All In One如何使用 Figma 给文字添加背景色https://www.figma.com/design/ solutionshttps://www.youtube.com/watch?v=j1UT8ezXAXI…

app手机元素定位方式

方式一:采用uiautomatorviewer元素定位 ①这个定位方式有缺陷也就是它只能识别Android8以下的系统,8及以上的系统就无法定位了 ②位置:这个工具是位于安装的SDK下的tools文件下,我的安装路径如下③双击打开这个工具就行,再运行的页面点击 方式二:安装Appium-Inspector ①下…

从0到0.1学习实践盒子模型

从0到0.1学习实践盒子模型 盒子模型概念 预备知识margin:外边距【两个元素之间的距离】 border:边框 padding:内边距【内容区域和边框距离】 height:文本高度 width:文本宽度content-box (形象图片)content-box--只计算内容区域的宽度和高度,边框和内边距不算在内。 .b…

Leetcode 445. 两数相加 II

1.题目基本信息 1.1.题目描述 给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。 你可以假设除了数字 0 之外,这两个数字都不会以零开头。 1.2.题目地址 https://leetcode.cn/problems/add…

Windows命令:时间延迟命令

延迟一段时间再执行下一条命令”。 一、利用ping实现延迟命令 这种延时手段是不精确的,因为每一次ping通的延迟不一样。 1、示例chcp 65001 @echo off echo 延时前:%time% ping /n 3 127.0.0.1 >nul echo 延时后:%time% pause 参数/n表示ping通的次数。127.0.0.1是本机ip…

电力施工作业绝缘手套识别系统

电力施工作业绝缘手套识别系统对电力作业人员在电力设备上进行施工作业时是否佩戴绝缘手套进行识别分析,当电力施工作业绝缘手套识别系统检测到作业人员未佩戴绝缘手套时立即抓拍存档同步回传给后台监控人员,提醒相关人员及时制止,及时规避更危险的触电事故发生。电力施工作…

sicp每日一题[2.24-2.27]

2.24-2.26没什么代码量,所以跟 2.27 一起发吧。Exercise 2.24Suppose we evaluate the expression (list 1 (list 2 (list 3 4))). Give the result printed by the interpreter, the corresponding box-and-pointer structure, and the interpretation of this as a tree (as…

ansible-cmdb简单使用

1、安装 官方:https://ansible-cmdb.readthedocs.io/en/latest/ wget https://github.com/fboender/ansible-cmdb/releases/download/1.27/ansible-cmdb-1.27-2.noarch.rpm yum -y install ./ansible-cmdb-1.27-2.noarch.rpm2、使用 首先,为你的主机生成 Asible 输出: mkdir…