# Map接口实现类
# 简要回答
HashMap: HashMap是基于哈希表实现的,可以提供快速的键值对存取,但是不保证迭代顺序。它允许null键和null值,但它是非线程安全的。LinkedHashMap: LinkedHashMap继承自HashMap,它通过内部维护的双向链表来维护元素的插入顺序或访问顺序。LinkedHashMap也允许null键和null值,但它也是非线程安全的。TreeMap: TreeMap是基于红黑树实现的,它按照键的自然顺序 或者是 自定义的比较器进行排序。TreeMap并不允许null键,它也是非线程安全的。ConcurrentHashMap: ConcurrentHashMap是目前常用的高性能的线程安全Map。它通过分段锁(JDK 1.7)或 CAS +synchronized(JDK 1.8+)来实现并发控制。ConcurrentHashMap不允许null键。Hashtable: Hashtable算是比较传统的线程安全Map,它的所有操作都通过synchronized关键字同步,因此性能较低。Hashtable既不允许null键,也不允许null值。Properties: 它是Hashtable的子类,主要用于读写键和值都是String类型的配置文件。
# 详细回答
- HashMap :
- 底层数据结构:
① 在 JDK 1.8 之前,HashMap的底层就是数组 + 链表。
② 在 JDK 1.8 及之后,如果table数组中某一条链表的元素个数达到或超过了TREEIFY_THRESHOLD(默认是8),并且table数组的长度达到或超过了MIN_TREEIFY_CAPACITY(默认是64),底层就会对该链表进行树化,将其转化为一棵红黑树。当红黑树的节点数量减少到 6 时,则会又退化为链表。 - 核心特性:
① 无序性: HashMap不保证键值对的迭代顺序。
② 允许null键和null值: HashMap允许有null键但最多只能有一个null键,null值可以同时存在多个。
③ 非线程安全: 在多线程环境下并发修改HashMap可能导致数据不一致 或者 出现ConcurrentModificationException。 - 时间复杂度:
① 在理想的哈希分布下,HashMap的put(),get(),remove()等操作的平均时间复杂度均为 O(1) 。
② 在最坏情况下(例如所有键的哈希值都相同,导致链表过长),这时时间复杂度会退化为 O(N) ,但 JDK 1.8 引入红黑树后,这种情况的概率大大降低。 - 适用场景:
① 绝大多数需要存储键值对的场景。 它是 Java 中使用最广泛的Map实现。
② 不需要保持元素插入顺序或对键进行排序的场景。
- 底层数据结构:
- LinkedHashMap :
- 底层数据结构:
①LinkedHashMap继承自HashMap,因此其底层也基于 数组 + 链表/红黑树(同 JDK 1.8+ 的HashMap)。
② 在此基础上,LinkedHashMap额外维护了一个双向链表,这个链表连接了Map中所有的键值对(Entry 或 Node),从而能够保持元素的特定顺序。 - 核心特性:
① 保持插入顺序(默认): 默认情况下,迭代器会按照元素插入的顺序返回键值对。
② 保持访问顺序(LRU 策略): 可以通过构造函数设置accessOrder参数为true,使其按照元素的最近访问顺序(即 LRU 策略,最近访问的元素会被移到链表末尾)进行排序。
③ 允许null键和null值: 同HashMap。
④ 非线程安全: 同HashMap。 - 时间复杂度:
①put(),get(),remove()等操作的平均时间复杂度为 O(1) 。链表的维护操作对性能影响很小。 - 适用场景:
① 需要保持元素插入顺序的缓存或处理队列。
② 实现 LRU (Least Recently Used) 缓存策略: 通过重写removeEldestEntry方法,可以在Map达到指定容量上限时自动移除最不常用的元素,非常适合作为固定大小的缓存。
- 底层数据结构:
- TreeMap :
- 底层数据结构:
①TreeMap的底层是基于**红黑树(Red-Black Tree)**实现的。红黑树是一种自平衡的二叉查找树,它能保证树的高度保持对数级别,从而提供稳定的性能。 - 核心特性:
① 按键排序: 键值对会根据键的自然顺序(即键类必须实现Comparable接口)或在构造时提供的Comparator进行排序。
② 不允许null键: 因为需要对键进行比较操作来确定其在树中的位置,而null无法参与比较,所以TreeMap不允许null键。
③ 允许null值: 可以有多个null值。
④ 非线程安全: 同HashMap。 - 时间复杂度:
①put(),get(),remove()等操作的时间复杂度为 O(logN) ,其中 N 是Map中元素的数量。这是因为红黑树的高度是 O(logN)。 - 适用场景:
① 需要对键进行排序的场景。 例如,按字母顺序存储用户,按日期存储事件,或者需要获取某个范围内的键值对。
② 需要执行范围查询(如subMap()、headMap()、tailMap())的场景。
③ 需要高效地查找最小/最大键、或键的最近邻居的场景。
- 底层数据结构:
- ConcurrentHashMap :
- 底层数据结构:
① JDK 1.7 及之前: 采用**分段锁(Segment)**的机制。ConcurrentHashMap内部维护一个Segment数组,每个Segment都是一个独立的ReentrantLock,并管理着一个哈希表(类似于HashMap)。通过对不同的Segment加锁,实现了对Map的分段并发控制,降低了锁的粒度。
② JDK 1.8 及之后(包括 JDK 17.0): 放弃了Segment概念,改用 CAS (Compare And Swap) +synchronized关键字(针对哈希桶的头节点)+ 数组 + 链表/红黑树。在链表/红黑树的头节点上使用synchronized锁,进一步降低了锁的粒度,提高了并发性能。读操作通常不需要加锁,写操作只锁住当前操作的哈希桶。 - 核心特性:
① 高性能线程安全: 提供了比Hashtable更好的并发性能,读操作通常不需要加锁。
② 不允许null键: 但允许null值(JDK 8+)。
③ 无序: 不保证迭代顺序。 - 时间复杂度:
①put(),get(),remove()等操作的平均时间复杂度为 O(1) 。 - 适用场景:
① 高并发环境下需要线程安全的键值对存储。 例如,共享缓存、会话管理、计数器等。它是现代 Java 并发编程中Map的首选。
- 底层数据结构:
- Hashtable :
- 底层数据结构:
①Hashtable的底层基于数组 + 链表,与 JDK 1.8 之前的HashMap类似。 - 核心特性:
① 线程安全:Hashtable的所有公共方法都使用了synchronized关键字进行修饰,这意味着在任何时候只有一个线程可以访问Hashtable的方法。这种粗粒度的全表锁机制保证了线程安全。
② 不允许null键和null值: 如果尝试插入null键或null值,会抛出NullPointerException。
③ 无序性: 不保证迭代顺序。 - 时间复杂度:
① 在单线程环境下,put(),get(),remove()等操作的平均时间复杂度为 O(1) 。
② 但在高并发环境下,由于其粗粒度的全表锁,多个线程的竞争会导致严重的性能瓶颈,实际性能会急剧下降。 - 适用场景:
① 基本已被淘汰,不推荐在新代码中使用。 主要出现在一些遗留系统中,现代应用应优先选择ConcurrentHashMap。
- 底层数据结构:
- Properties :
- 底层数据结构:
①Properties类继承自Hashtable。 - 核心特性:
① 键和值都必须是String类型: 这是Properties最显著的特点,它专门设计用于存储字符串类型的键值对。
② 常用于与 I/O 流结合: 提供了load()和store()方法,可以直接从输入流加载键值对或将键值对保存到输出流,通常用于读写.properties文件。
③ 线程安全: 由于继承自Hashtable,它也具备线程安全特性,但同样面临性能瓶颈。 - 时间复杂度:
① 同Hashtable,平均时间复杂度为 O(1) 。 - 适用场景:
① 读写.properties配置文件: 这是其最主要的用途,例如存储数据库连接信息、应用程序配置参数等。
- 底层数据结构:
# 知识图解
- Map类实现类的选择策略,如下图所示 ;

- Java集合框架体系图,如下图所示:

# 知识拓展
Collections.synchronizedMap(Map<K,V> m):- 这是一个工具方法,可以将任何非线程安全的
Map(如HashMap、LinkedHashMap、TreeMap)包装成一个线程安全的Map。 - 它的实现机制是对传入的
Map对象进行包装,并在每个方法调用时对整个Map对象加锁。虽然能提供线程安全,但由于是粗粒度的锁,其并发性能通常不如ConcurrentHashMap。在并发度要求不高的场景下可以使用。
- 这是一个工具方法,可以将任何非线程安全的
WeakHashMap:- 其键是弱引用,当键不再被其他强引用指向时,即使
WeakHashMap中还存有它的引用,垃圾回收器也会回收这个键值对。 - 适用于实现简单的缓存,当内存不足时,可以自动清理不再被引用的键值对,避免内存泄漏。
- 其键是弱引用,当键不再被其他强引用指向时,即使
评论
验证登录状态...