1. 基本概念
Map (接口)
2. 核心区别
-
定义:
java.util.Map是一个表示键值对(key-value)映射的接口 -
特性:
-
存储键值对数据
-
键(key)不能重复
-
每个键最多映射到一个值
-
-
主要方法:
V put(K key, V value) // 添加键值对 V get(Object key) // 根据键获取值 V remove(Object key) // 删除键值对 boolean containsKey(Object key) // 检查是否包含键 Set<K> keySet() // 获取所有键的集合HashMap (实现类)
-
定义:
java.util.HashMap是 Map 接口的一个基于哈希表的实现 -
特性:
-
允许 null 键和 null 值
-
非线程安全
-
不保证元素的顺序
-
查找效率高(理想情况下O(1))
-
| 特性 | Map (接口) | HashMap (实现类) |
|---|---|---|
| 类型 | 接口 | 具体实现类 |
| 实现方式 | 无具体实现 | 基于哈希表实现 |
| 线程安全 | 接口本身不涉及线程安全问题 | 非线程安全 |
| 允许null | 取决于具体实现 | 允许null键和null值 |
| 顺序保证 | 不保证顺序 | 不保证顺序 |
| 性能 | 取决于实现 | 查找/插入/删除平均O(1) |
| 继承关系 | 顶级接口 | 实现Map接口 |
3. 底层实现原理
HashMap 的工作原理:
-
哈希函数:使用键的hashCode()计算哈希值
-
数组+链表/红黑树:
-
Java 8之前:数组+链表
-
Java 8及以后:数组+链表/红黑树(当链表长度>8时转换)
-
-
扩容机制:默认初始容量16,负载因子0.75,当size > 容量*负载因子时扩容为2倍
4. 使用场景
使用 Map 接口的情况:
-
编写通用代码,不依赖具体实现
-
需要多态性,可能使用不同Map实现
-
定义方法参数或返回值类型
使用 HashMap 的情况:
-
需要高效的键值对存储和访问
-
不关心元素顺序
-
单线程环境或已处理好线程安全问题
-
需要允许null键值
5. 代码示例
// 使用Map接口声明
Map<String, Integer> map = new HashMap<>();
// 添加元素
map.put("Apple", 10);
map.put("Banana", 5);
map.put("Orange", 8);
// 获取元素
int apples = map.get("Apple"); // 10
// 遍历Map
for(Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// Java 8+ 遍历
map.forEach((k, v) -> System.out.println(k + ": " + v));
6. 其他Map实现类比较
除了HashMap,Java还提供了多种Map实现:
-
TreeMap:基于红黑树实现,保持键的自然排序
-
LinkedHashMap:保持插入顺序或访问顺序
-
ConcurrentHashMap:线程安全版本
-
HashTable:古老的线程安全实现(不推荐使用)
7. 最佳实践
编程时尽量使用Map接口声明变量:
// 好 - 使用接口
Map<String, Integer> map = new HashMap<>();
// 不好 - 使用具体类
HashMap<String, Integer> map = new HashMap<>();
初始化时设置合理容量:
// 如果知道大概元素数量
Map<String, Integer> map = new HashMap<>(100);
注意键对象的hashCode()和equals()方法:
-
作为键的对象必须正确实现这两个方法
-
好的hashCode()实现能减少哈希冲突
线程安全考虑:
-
多线程环境下使用ConcurrentHashMap
-
或者使用Collections.synchronizedMap()包装
635

被折叠的 条评论
为什么被折叠?



