Java中HashMap和Hashtable的区别
Java中HashMap和Hashtable的区别
技术背景
在Java编程中,HashMap
和 Hashtable
都是用于存储键值对的数据结构,它们都利用哈希技术来存储唯一的键。Hashtable
是JDK 1.0中引入的遗留类,而 HashMap
是JDK 1.2中作为Java集合框架的一部分引入的。随着Java的发展,了解它们之间的区别对于选择合适的数据结构至关重要。
实现步骤
1. 同步性
- Hashtable:是同步的,这意味着同一时间只有一个线程可以修改哈希表。任何线程在对
Hashtable
进行更新操作之前,都必须获取该对象的锁,其他线程则需要等待锁被释放。这使得Hashtable
适合在多线程环境中使用,但会带来一定的性能开销。 - HashMap:是非同步的,不是线程安全的,因此在多线程环境中使用时,如果没有适当的同步代码,不能在多个线程之间共享。不过,在单线程环境中,由于不需要进行同步操作,
HashMap
的性能通常更好。
2. 对null的支持
- Hashtable:不允许使用null作为键或值。如果尝试插入null键或值,会抛出
NullPointerException
。 - HashMap:允许使用一个null键和任意数量的null值。
3. 迭代器和枚举器
- Hashtable:可以通过枚举器(
Enumeration
)和迭代器(Iterator
)进行遍历。枚举器是fail-safe的,即当集合在迭代过程中被修改时,不会抛出异常;而迭代器是fail-fast的,如果在迭代过程中集合被结构修改(除了迭代器自身的remove()
方法),会抛出ConcurrentModificationException
。 - HashMap:只能通过迭代器进行遍历,并且迭代器是fail-fast的。
4. 继承关系
- Hashtable:继承自
Dictionary
类,该类现在已被视为过时,从JDK 1.2开始,Hashtable
被重新设计以实现Map
接口,成为Java集合框架的一员。 - HashMap:继承自
AbstractMap
类,并且从一开始就是Java集合框架的成员。
5. 初始容量和负载因子
- Hashtable:默认初始容量为11,负载因子为0.75。
- HashMap:默认初始容量为16,负载因子同样为0.75。
6. 结构修改处理(Java 8及以后)
- Hashtable:在发生哈希冲突时,会将映射条目存储在链表中。
- HashMap:在Java 8中,如果哈希桶中的节点数量超过8个,链表会转换为红黑树;当桶中的节点数量减少到6个以下时,红黑树会转换回链表。这一改进提高了在高哈希冲突情况下的查找性能,最坏情况下的时间复杂度从O(n)降低到O(log n)。
核心代码
Hashtable示例
1 |
|
HashMap示例
1 |
|
最佳实践
- 单线程环境:如果应用程序是单线程的,建议使用
HashMap
,因为它的性能更好,并且允许使用null键和值。 - 多线程环境:
- 如果需要完全的线程安全,可以使用
Hashtable
,但要注意其性能开销。 - 更好的选择是使用
ConcurrentHashMap
,它是Java 5引入的,提供了比Hashtable
更好的可扩展性。 - 如果只需要在某些操作上进行同步,可以使用
Collections.synchronizedMap()
方法将HashMap
转换为同步的映射。
- 如果需要完全的线程安全,可以使用
1 |
|
常见问题
1. 为什么 Hashtable
被认为是遗留类?
Hashtable
是JDK 1.0中引入的,随着Java集合框架的发展,它的设计和功能已经有了更好的替代方案。例如,ConcurrentHashMap
提供了更好的并发性能,而 HashMap
在单线程环境中性能更优。此外,Hashtable
继承自过时的 Dictionary
类,其API也不如现代的集合类简洁和灵活。
2. HashMap
的迭代器为什么是fail-fast的?
HashMap
的迭代器设计为fail-fast是为了快速检测到并发修改,避免在迭代过程中出现数据不一致的问题。当检测到并发修改时,迭代器会立即抛出 ConcurrentModificationException
,提醒开发者需要处理并发问题。
3. ConcurrentHashMap
和 Hashtable
有什么区别?
- 同步粒度:
Hashtable
对整个哈希表进行同步,同一时间只有一个线程可以访问;而ConcurrentHashMap
采用分段锁或CAS(Compare-And-Swap)机制,允许多个线程同时访问不同的段,提高了并发性能。 - 读操作:
Hashtable
的读操作也是同步的,而ConcurrentHashMap
的读操作通常不需要加锁,因此在高并发读的场景下性能更好。 - 对null的支持:
ConcurrentHashMap
不允许使用null键或值,与Hashtable
相同。
Java中HashMap和Hashtable的区别
https://119291.xyz/posts/2025-04-18.differences-between-hashmap-and-hashtable-in-java/