首页 > 编程语言 >Java中Map接口的学习

Java中Map接口的学习

时间:2024-09-24 12:01:15浏览次数:7  
标签:Map Java key 映射 接口 键值 哈希 LinkedHashMap HashMap

Map接口


目录

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对象,代表一个键值对。

标签:Map,Java,key,映射,接口,键值,哈希,LinkedHashMap,HashMap
From: https://www.cnblogs.com/BingBing-8888/p/18428882

相关文章

  • 第二天:Java练习
    1,BMI体质指数测试BMI=体重(kg)/(身高*身高),接收输入的身高和体重,然后输出结果:过轻:低于18.5正常:18.5~22.9偏胖:23~24.9肥胖:25~29.9重度肥胖:高于30packagejava4;importjava.util.Scanner;publicclasspractise{publicstaticvoidmain(String[]args){......
  • 07 Java 类与对象(pta)
    函数题##1classTest{publicintsum(double...values)//接受若干个,最后一个为valus{intresult=0;for(doublei:values){result+=i;}returnresult;}}##2classPoint{i......
  • 股票量化交易接口,量化交易如何与券商接口
    Python股票接口实现查询账户,提交订单,自动交易(1)Python股票程序交易接口查账,提交订单,自动交易(2)量化交易与券商接口的对接涉及多个步骤和流程,具体如下:了解券商提供的API接口:在开始之前,需要熟悉券商提供的API接口文档,包括接口参数、返回值、调用方式等信息。券商可能提供......
  • Java语言实现便利店货物管理程序
    摘要随着便利店行业的快速发展,货物管理已成为提升经营效率和顾客满意度的关键环节。本文将详细介绍如何用Java语言编写一个便利店货物管理程序。该程序包含货物的进货、销售、库存管理以及销售统计等功能,旨在为便利店的日常管理提供支持。通过示例代码和详细解释,读者将能够学会如何......
  • go基础-4.数组、切片、map
    数组数组(Array)是一种非常常见的数据类型,几乎所有的计算机编程语言中都会用到它数组里的元素必须全部为同一类型,要嘛全部是字符串,要嘛全部是整数声明数组时,必须指定其长度或者大小packagemainimport"fmt"funcmain(){vararray[3]int=[3]int{1,2,3}fmt.Pr......
  • go基础-11.接口
    接口是一组仅包含方法名、参数、返回值的未具体实现的方法的集合packagemainimport"fmt"//Animal定义一个animal的接口,它有唱,跳,rap的方法typeAnimalinterface{sing()jump()rap()}//Chicken需要全部实现这些接口typeChickenstruct{Namestring}......
  • HashMap和HashTable
    HashMaphashMap基于哈希表,底层结果由数组实现,添加到map里的元素以key-value的形式存储在数组中,在数组中key-value已一个实体的形式存储, 也就是继承至map接口中的entry,下图是map源码enrty既然hashMap是基于哈希表,就会出现一个问题,就是哈希值重复,专业术语叫哈......
  • 为什么要使用API接口获取数据?
    在当今数字化和信息化的时代,数据已成为企业和开发者最宝贵的资产之一。API(应用程序编程接口)作为一种标准化的数据获取方式,正在迅速成为获取和共享数据的首选手段。本文将探讨为什么使用API接口获取数据是现代开发的最佳实践。1.高效的数据访问API接口提供了一种高效的方式......
  • java知识:什么是GC?GC调优思路又有哪些
    GC是什么    GC,全称GarbageCollection,即垃圾收集或垃圾回收,是一种自动内存管理机制。在计算机科学中,特别是在Java等编程语言中,GC扮演着至关重要的角色。当程序中的某些对象不再被需要时,垃圾收集器会自动识别这些对象并释放它们所占用的内存空间,以防止内存泄露,确保程......
  • FormatConvertedBitmap DestinationFormat Gray32Float BlackWhite
     <Windowx:Class="WpfApp410.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.micros......