Hashtable
和 HashMap
是 Java 中两种常用的哈希表实现,虽然功能类似(都用于存储键值对),但在设计、性能、线程安全等方面有显著区别。以下是它们的核心区别:
1. 线程安全性
特性 | Hashtable | HashMap |
---|
线程安全 | 是(所有方法用 synchronized 修饰) | 否(非同步,需手动保证线程安全) |
适用场景 | 多线程环境 | 单线程环境,或需手动控制同步的场景 |
示例:
Hashtable<String, Integer> table = new Hashtable<>();
table.put("key1", 1);
HashMap<String, Integer> map = new HashMap<>();
map.put("key2", 2);
2. Null 值支持
特性 | Hashtable | HashMap |
---|
允许 null 键 | 否(抛 NullPointerException ) | 是(允许一个 null 键) |
允许 null 值 | 否(抛 NullPointerException ) | 是(允许多个 null 值) |
示例:
table.put(null, 1);
table.put("key", null);
map.put(null, 1);
map.put("key", null);
3. 性能对比
特性 | Hashtable | HashMap |
---|
性能 | 较低(同步操作带来额外开销) | 较高(无同步开销) |
扩容机制 | 默认初始容量 11,扩容为 2n+1 | 默认初始容量 16,扩容为 2n |
4. 继承体系
类 | Hashtable | HashMap |
---|
父类 | Dictionary (已过时) | AbstractMap |
实现接口 | Map | Map |
5. 迭代器
特性 | Hashtable | HashMap |
---|
遍历方式 | 使用 Enumeration (旧接口) | 使用 Iterator (支持快速失败) |
遍历性能 | 较低 | 较高(Iterator 更高效) |
示例:
Enumeration<String> keys = table.keys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
}
Iterator<String> it = map.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
}
6. 哈希冲突解决
- 共同点:均使用 链地址法(数组+链表/红黑树)。
- 区别:
- HashMap(JDK 8+):当链表长度 ≥8 时,链表转为红黑树,提高查询效率。
- Hashtable:始终使用链表,无红黑树优化。
总结:如何选择?
场景 | 推荐选择 | 理由 |
---|
多线程环境 | ConcurrentHashMap | 比 Hashtable 性能更高,分段锁优化 |
单线程环境 | HashMap | 无锁,性能最优 |
遗留代码兼容 | Hashtable | 仅需兼容旧系统时使用 |
现代开发建议:
- 优先使用
HashMap
(单线程)或 ConcurrentHashMap
(多线程)。 Hashtable
已逐渐被淘汰,仅需在兼容旧代码时使用。