Java Map 集合全维度解析
·
一、Map 接口通用核心方法(所有实现类均继承)
先统一梳理 Map 接口的基础方法,按功能分类,便于理解各实现类方法的底层逻辑:
| 方法分类 | 核心方法 | 方法作用 |
|---|---|---|
| 基础 CRUD | V put(K key, V value) | 插入/替换键值对:键存在则替换值,返回旧值;键不存在则插入,返回 null |
V putIfAbsent(K key, V value) | 原子插入:仅当键不存在时插入,返回 null;键存在则返回现有值(JDK8+) | |
V get(Object key) | 根据键取值:键不存在返回 null | |
V getOrDefault(Object key, V defaultValue) | 根据键取值:键不存在返回默认值(JDK8+) | |
V remove(Object key) | 删除键值对:返回被删除的值,键不存在返回 null | |
boolean remove(Object key, Object value) | 条件删除:仅当键对应值等于指定值时删除,返回是否成功(JDK8+) | |
V replace(K key, V value) | 替换:仅当键存在时替换值,返回旧值;键不存在返回 null | |
boolean replace(K key, V oldValue, V newValue) | 条件替换:仅当键对应旧值匹配时替换,返回是否成功 | |
void clear() | 清空所有键值对 | |
| 批量操作 | void putAll(Map<? extends K, ? extends V> m) | 批量插入另一个 Map 的所有键值对 |
boolean containsKey(Object key) | 判断是否包含指定键 | |
boolean containsValue(Object value) | 判断是否包含指定值(遍历所有值,效率低) | |
| 视图操作 | Set<K> keySet() | 返回所有键的 Set 视图(修改视图会同步修改原 Map) |
Collection<V> values() | 返回所有值的 Collection 视图(同上) | |
Set<Map.Entry<K, V>> entrySet() | 返回键值对 Entry 的 Set 视图(遍历 Map 的最优方式) | |
| 辅助操作 | int size() | 返回键值对数量 |
boolean isEmpty() | 判断是否为空 | |
boolean equals(Object o) | 判断两个 Map 的键值对完全相等 | |
int hashCode() | 返回 Map 的哈希值(基于所有 Entry 的哈希值) | |
| JDK8+ 函数式 | V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) | 计算并更新键的值:函数接收键和旧值,返回新值(null 则删除该键) |
V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) | 仅当键不存在/值为 null 时,通过函数计算值并插入(实现懒加载) | |
V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) | 仅当键存在且值非 null 时,计算并更新值 | |
V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) | 合并值:键不存在则插入,存在则通过函数合并新旧值(null 则删除) |
二、各 Map 实现类详解(特性+特有方法)
1. HashMap(通用型)
核心特性(复用前文,精简)
- 底层:JDK1.8=数组+链表+红黑树;非线程安全;无序;允许 1 个 null 键、多个 null 值;平均 O(1) 性能。
特有/重写方法(无特有方法,仅重写通用方法)
- 重写
hash(Object key):计算键的哈希值(JDK1.8 优化:(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)),减少哈希冲突。 - 重写
getNode(int hash, Object key):核心查询方法,先定位数组索引,再遍历链表/红黑树找键。
方法使用注意
put(null, value):null 键的哈希值固定为 0,存入数组索引 0 位置。- 遍历推荐
entrySet(),避免keySet()+get()重复计算哈希。
2. LinkedHashMap(有序 HashMap 子类)
核心特性
- 底层:HashMap+双向链表;非线程安全;支持插入/访问顺序;允许 null 键值;略低于 HashMap 性能。
特有方法/重写方法
| 特有/重写方法 | 作用 |
|---|---|
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) | 可重写方法:返回 true 时移除最老的 Entry(实现 LRU 缓存核心) |
构造方法 LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) | accessOrder=true 开启访问顺序(get/put 后元素移到链表尾部),默认 false(插入顺序) |
方法使用示例(LRU 缓存)
// 最多缓存5个元素,超过则移除最老的
LinkedHashMap<String, Integer> lruMap = new LinkedHashMap<>(16, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
return size() > 5;
}
};
3. TreeMap(有序排序)
核心特性
- 底层:红黑树;非线程安全;按键自然/定制排序;自然排序不允许 null 键;O(logn) 性能。
特有方法(导航/排序相关)
| 特有方法 | 作用 |
|---|---|
K firstKey() | 返回最小键(红黑树最左节点) |
K lastKey() | 返回最大键(红黑树最右节点) |
K ceilingKey(K key) | 返回≥key 的最小键,无则返回 null |
K floorKey(K key) | 返回≤key 的最大键,无则返回 null |
K higherKey(K key) | 返回>key 的最小键,无则返回 null |
K lowerKey(K key) | 返回<key 的最大键,无则返回 null |
NavigableSet<K> navigableKeySet() | 返回可导航的键 Set(支持逆序、范围查询) |
Map.Entry<K, V> firstEntry() | 返回最小键的 Entry |
Map.Entry<K, V> lastEntry() | 返回最大键的 Entry |
Map.Entry<K, V> pollFirstEntry() | 移除并返回最小键的 Entry |
Map.Entry<K, V> pollLastEntry() | 移除并返回最大键的 Entry |
SortedMap<K, V> subMap(K fromKey, K toKey) | 返回[fromKey, toKey) 范围的子 Map(视图,修改同步原 Map) |
SortedMap<K, V> headMap(K toKey) | 返回<toKey 的子 Map |
SortedMap<K, V> tailMap(K fromKey) | 返回≥fromKey 的子 Map |
Comparator<? super K> comparator() | 返回排序用的 Comparator,自然排序返回 null |
方法使用注意
put(key, value):若键未实现Comparable且无自定义Comparator,抛ClassCastException。- 导航方法(如
ceilingKey)是 TreeMap 核心优势,适合范围查询场景。
4. Hashtable(古老线程安全)
核心特性
- 底层:数组+链表;线程安全(方法加
synchronized);无序;不允许 null 键值;性能极低。
特有/重写方法
- 所有方法均加
synchronized(如public synchronized V put(K key, V value)),锁整个 Hashtable。 - 重写
contains(Object value):等价于containsValue(value)(历史遗留方法,不推荐使用)。
方法使用注意
put(null, value)直接抛NullPointerException,与 HashMap 差异核心。- 已被 ConcurrentHashMap 替代,仅兼容老代码。
5. ConcurrentHashMap(高并发线程安全)
核心特性
- 底层:JDK1.8=数组+链表+红黑树+CAS+锁单个 Node;高并发安全;无序;不允许 null 键值;并发性能最优。
特有方法(原子操作/并发相关)
| 特有方法 | 作用 |
|---|---|
V putIfAbsent(K key, V value) | 原子插入(核心并发方法):避免多线程重复插入,比 put 安全 |
boolean remove(Object key, Object value) | 原子条件删除:多线程下避免误删 |
boolean replace(K key, V oldValue, V newValue) | 原子条件替换 |
V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) | 原子懒加载插入(JDK8+),避免并发下重复计算 |
int mappingCount() | 返回键值对数量(比 size() 更准确,高并发下 size() 是近似值) |
ConcurrentNavigableMap<K, V> subMap(...) | 仅 JDK1.8 支持可导航子 Map(分段锁版本无) |
方法使用注意
- 无
keySet().iterator().remove()方法(迭代器不支持删除,需用remove(key))。 - 所有原子方法(putIfAbsent、computeIfAbsent)是并发场景的核心,避免手动加锁。
6. WeakHashMap(弱引用键,自动回收)
核心特性
- 底层:数组+链表;非线程安全;无序;键为弱引用,GC 自动回收无强引用的键;允许 null 键值。
特有/重写方法(无特有方法,核心是弱引用逻辑)
- 重写
expungeStaleEntries():遍历并移除被 GC 回收的键对应的 Entry(put/get 时自动触发)。
方法使用注意
get(key)会触发清理过期 Entry,因此遍历前建议先调用size()触发清理。- 避免值强引用键:若
value -> key形成强引用,键无法被 GC 回收,导致内存泄漏。
7. IdentityHashMap(引用相等判断)
核心特性
- 底层:数组+链表;非线程安全;无序;键相等判断用
==(引用)而非equals();允许 null 键值。
特有/重写方法(核心是重写键相等逻辑)
- 重写
hash(Object key):直接用 System.identityHashCode(key)(基于对象引用地址)。 - 重写
eq(Object k1, Object k2):返回k1 == k2(而非k1.equals(k2))。
方法使用示例
IdentityHashMap<String, Integer> map = new IdentityHashMap<>();
String s1 = new String("a");
String s2 = new String("a");
map.put(s1, 1);
map.put(s2, 2);
System.out.println(map.size()); // 2(s1和s2引用不同,视为不同键)
8. EnumMap(枚举键,极致性能)
核心特性
- 底层:数组(基于枚举 ordinal() 索引);非线程安全;按枚举声明顺序;不允许 null 键;O(1) 性能。
特有方法/构造方法
| 特有方法/构造方法 | 作用 |
|---|---|
EnumMap(Class<K> keyType) | 构造方法:必须指定枚举类(确定数组长度) |
EnumMap(EnumMap<K, ? extends V> m) | 复制另一个 EnumMap 的键值对 |
EnumMap(Map<K, ? extends V> m) | 从普通 Map 复制(仅当键为枚举时) |
Set<K> keySet() | 返回按枚举声明顺序的键 Set(数组遍历,效率极高) |
方法使用注意
put(key, value):key 必须是指定枚举类的实例,否则抛NullPointerException/ClassCastException。- 遍历
values()直接按数组索引遍历,性能远高于 HashMap。
三、全维度对比表(特性+方法核心差异)
| 特性/方法 | HashMap | LinkedHashMap | TreeMap | Hashtable | ConcurrentHashMap | WeakHashMap | IdentityHashMap | EnumMap |
|---|---|---|---|---|---|---|---|---|
| 核心特性(复用) | 通用、高性能、无序 | 插入/访问有序 | 按键排序、导航方法 | 线程安全(锁全表) | 高并发、原子方法 | 弱引用键、自动回收 | 引用相等判断 | 枚举键、极致性能 |
| 特有核心方法 | 无 | removeEldestEntry、accessOrder构造 | firstKey/ceilingKey等导航方法 | contains(等价containsValue) | putIfAbsent、mappingCount | expungeStaleEntries(隐式) | 基于==的hash/eq | 枚举专属构造方法 |
| 线程安全方法 | 无 | 无 | 无 | 所有方法synchronized | CAS+锁Node、原子方法 | 无 | 无 | 无 |
| null 处理(方法) | put(null, v) 允许 | 同HashMap | 自然排序put(null)抛异常 | put(null)抛异常 | put(null)抛异常 | 同HashMap | 同HashMap | put(null)抛异常 |
| 遍历性能 | 高(entrySet) | 更高(双向链表) | 中(红黑树遍历) | 低(同步+链表) | 高(分段锁/Node锁) | 同HashMap | 同HashMap | 极高(数组遍历) |
| 原子操作方法 | 无(JDK8+ compute 非原子) | 同HashMap | 同HashMap | 有(synchronized) | 丰富(putIfAbsent等) | 同HashMap | 同HashMap | 无 |
四、方法使用关键注意事项
-
线程安全方法选择:
- 多线程写操作:优先用 ConcurrentHashMap 的
putIfAbsent/computeIfAbsent,而非Collections.synchronizedMap+普通 put。 - 避免在 ConcurrentHashMap 中使用
forEach时修改元素(迭代器弱一致性,不会抛 ConcurrentModificationException)。
- 多线程写操作:优先用 ConcurrentHashMap 的
-
有序遍历方法:
- 插入顺序:LinkedHashMap(默认)的
entrySet遍历。 - 键排序:TreeMap 的
navigableKeySet或subMap范围遍历。 - 枚举顺序:EnumMap 的
keySet直接遍历(按枚举声明顺序)。
- 插入顺序:LinkedHashMap(默认)的
-
性能优化方法:
- HashMap/LinkedHashMap 初始化时指定容量(
new HashMap(100)),避免扩容开销。 - 避免用
containsValue(全量遍历),可维护额外 Set 存储值实现快速查询。 - EnumMap 替代 HashMap(键为枚举时),方法调用性能提升 50%+。
- HashMap/LinkedHashMap 初始化时指定容量(
-
内存安全方法:
- WeakHashMap 中避免值引用键:可将值改为弱引用,或用
WeakReference包装键。 - IdentityHashMap 仅用于“对象引用唯一”场景,避免误判(如 String 常量池对象)。
- WeakHashMap 中避免值引用键:可将值改为弱引用,或用
五、特性+方法 综合选型建议
| 场景需求 | 首选 Map + 核心方法 |
|---|---|
| 单线程、高性能、无序 | HashMap + put/get/entrySet 遍历 |
| 单线程、插入/访问顺序、LRU缓存 | LinkedHashMap + 重写 removeEldestEntry + accessOrder=true |
| 单线程、按键排序、范围查询 | TreeMap + ceilingKey/floorKey/subMap |
| 多线程、高并发、原子操作 | ConcurrentHashMap + putIfAbsent/computeIfAbsent |
| 缓存、自动清理无引用键 | WeakHashMap + get/put(自动触发 expungeStaleEntries) |
| 区分对象引用(== 判断) | IdentityHashMap + put/get(基于引用哈希) |
| 键为枚举、极致性能 | EnumMap + 构造指定枚举类 + keySet 遍历 |
| 老项目兼容 | Hashtable(替换为 ConcurrentHashMap) |
更多推荐


所有评论(0)