目录
一、Java Map接口及其常见实现类
Map接口定义与特性
Map接口是Java集合框架中的一个重要接口,它提供了一种键值对(Key-Value Pair)的存储结构。Map的主要特点和特性包括:
-
键值对存储:Map中的每个元素都包含一个唯一的键(Key)和与之关联的值(Value)。键和值可以是任何非null的对象,但键必须唯一,即一个Map中不能有两个相同的键。
-
键唯一:Map通过键来访问与其关联的值,因此键必须具有良好的散列性(对于HashMap等基于哈希表的实现)或可比较性(对于TreeMap等基于排序树的实现)。当尝试插入或替换具有相同键的新元素时,旧值将被覆盖。
-
常用方法:Map接口提供了丰富的操作方法,如
put(key, value)
插入键值对、get(key)
通过键获取值、remove(key)
删除键值对、containsKey(key)
检查是否存在指定键、size()
返回元素数量等。此外,还有clear()
清空Map、isEmpty()
检查是否为空、keySet()
获取所有键组成的Set视图、values()
获取所有值组成的Collection视图、entrySet()
获取所有键值对组成的Set视图等。 -
遍历方式:
- 迭代器遍历:通过调用
entrySet().iterator()
获取迭代器,然后使用hasNext()
和next()
遍历所有键值对。每个键值对以Map.Entry<K, V>
形式呈现,可以访问其getKey()
、getValue()
等方法。 - 增强for循环遍历:使用
for (Map.Entry<K, V> entry : map.entrySet())
语句遍历所有键值对。 - Stream API遍历:Java 8及以上版本引入了Stream API,可通过
map.entrySet().stream()
创建键值对的Stream,进而进行链式操作(如过滤、映射、聚合等)。
- 迭代器遍历:通过调用
HashMap
HashMap是Map接口最常用的实现类之一,其基于哈希表(Hash Table)实现。特点和适用场景如下:
-
实现原理:HashMap内部使用数组+链表/红黑树(Java 8引入)的数据结构。每个键值对存储在一个称为桶(Bucket)的结构中,通过键的哈希码(hashCode)确定其在数组中的索引。当多个键哈希到同一个桶时,形成链表或红黑树(当链表长度超过阈值时转换为树)。
-
优点:
- 查找速度快:通过哈希函数快速定位键值对,平均时间复杂度接近O(1)。
- 空间效率较高:不需要额外的空间存储元素之间的关系,仅需存储键值对本身。
-
缺点:
- 不保证元素顺序:插入和访问元素的顺序与实际存储顺序可能不一致,且顺序会随操作动态变化。
- 线程不安全:在多线程环境下未做同步控制,如需在并发环境中安全使用,应选用ConcurrentHashMap或手动同步。
-
适用场景:适用于对插入、删除、查找等操作有较高性能要求,且不关心元素顺序,且仅在单线程或已做外部同步的情况下使用的场景。
TreeMap
TreeMap基于红黑树(Red-Black Tree)实现,提供自动排序功能。特点和适用场景如下:
-
实现原理:TreeMap内部使用红黑树存储键值对,键必须实现
Comparable
接口(或提供Comparator
)。红黑树保证了键的有序性,且插入、删除、查找等操作具有对数时间复杂度(O(log n))。 -
优点:
- 自动排序:键按自然顺序或自定义比较器顺序排列,可以通过
firstKey()
、lastKey()
、subMap()
等方法方便地进行范围查询。 - 查询效率稳定:相比HashMap,虽然平均查找时间稍慢,但不受哈希冲突影响,性能更为稳定。
- 自动排序:键按自然顺序或自定义比较器顺序排列,可以通过
-
缺点:
- 查询速度较HashMap慢:由于红黑树的性质,查找、插入、删除等操作的时间复杂度为O(log n),比HashMap的平均O(1)略慢。
- 线程不安全:与HashMap类似,未做线程同步,不适合在并发环境中直接使用。
-
适用场景:适用于需要键按特定顺序排列,且对查找性能要求较高,但不苛求达到哈希表级别的性能,且在单线程或已做外部同步的场景。
LinkedHashMap
LinkedHashMap继承自HashMap,同时实现了java.util.LinkedHashMap
接口,结合了HashMap与LinkedList的特点。特点和适用场景如下:
-
特点:
- 保持插入/访问顺序:默认情况下,LinkedHashMap维护键值对的插入顺序;通过构造函数指定
accessOrder=true
,可改为维护最近访问顺序(LRU缓存)。 - 内部使用双向链表:除了哈希表结构外,每个键值对还链接在一个双向链表中,用于维护元素的顺序。
- 保持插入/访问顺序:默认情况下,LinkedHashMap维护键值对的插入顺序;通过构造函数指定
-
优缺点:
- 保留插入/访问顺序:便于按照插入或访问顺序遍历元素,且顺序不受后续操作影响。
- 线程不安全:与HashMap和TreeMap一样,未提供线程同步。
-
适用场景:适用于需要保持元素插入或访问顺序,且在单线程或已做外部同步的场景,如缓存、历史记录等。
Hashtable与ConcurrentHashMap
Hashtable是早期JDK提供的线程安全Map实现,与HashMap类似,但进行了同步处理。特点和适用场景如下:
- 特点:
- 线程安全:所有操作都经过同步,避免了多线程环境下的数据不一致问题。
- 不推荐使用:由于同步粒度过粗(整个Map加锁),在高并发场景下性能较低,且不支持null键和null值。
ConcurrentHashMap是JDK 1.5引入的并发友好的Map实现,提供了细粒度的锁机制,提高了并发性能。特点和适用场景如下:
- 特点:
- 线程安全且高效:使用分段锁(Segment Lock)实现细粒度的并发控制,多个修改操作可以并行进行,性能优于同步的HashMap和Hashtable。
- 支持null键和null值:与HashMap类似,允许插入null键和null值。
综上,Java中的Map接口及其常见实现类各有特点,选择时应根据实际需求(如是否需要排序、是否需要线程安全、是否在意插入/访问顺序等)和性能要求来决定使用哪一种。在并发环境中,优先考虑使用ConcurrentHashMap。
标签:Map,顺序,Java,HashMap,插入,Set,键值,线程 From: https://blog.csdn.net/m0_61635718/article/details/137347085