问:Java中HashMap和Hashtable区别,知多少?
维度 | HashMap | Hashtable |
---|---|---|
父类 | AbstractMap | Dictionary |
接口实现 | Map, Cloneable, Serializable | Map, Cloneable, Serializable |
提供的额外方法 | 无 | elements(), contains() |
对null的支持 | key可以为null(唯一),value可以为null | key和value都不能为null |
线程安全性 | 非线程安全 | 线程安全(方法上有synchronized) |
性能 | 高效,非同步开销 | 较低,同步开销 |
初始容量/扩充容量 | 初始容量16,扩充为2倍 | 初始容量11,扩充为2倍+1 |
计算hash值方法 | 自定义hash()方法 | 直接使用key的hashCode() |
示例
初始化与基本使用
import java.util.HashMap;
import java.util.Hashtable;
public class MapComparison {
public static void main(String[] args) {
// HashMap 示例
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("One", 1);
hashMap.put("Two", 2);
hashMap.put(null, 3); // key可以为null
System.out.println("HashMap: " + hashMap);
// Hashtable 示例
Hashtable<String, Integer> hashtable = new Hashtable<>();
hashtable.put("One", 1);
hashtable.put("Two", 2);
// hashtable.put(null, 3); // 编译错误,key不能为null
System.out.println("Hashtable: " + hashtable);
// Hashtable 的 extra 方法
// 注意:由于这些方法是Hashtable特有的,因此不能在HashMap上调用
System.out.println("Hashtable elements: " + hashtable.elements()); // 返回Enumeration对象
// System.out.println("Hashtable contains 1: " + hashtable.contains(1)); // 实际上应该使用containsValue(1)
System.out.println("Hashtable containsValue 1: " + hashtable.containsValue(1));
}
}
线程安全性
// 注意:这只是为了说明线程安全性的概念,并不是实际的并发测试代码
public class ThreadSafetyExample {
// 非线程安全的HashMap
private static HashMap<Integer, Integer> hashMap = new HashMap<>();
// 线程安全的Hashtable
private static Hashtable<Integer, Integer> hashtable = new Hashtable<>();
public static void main(String[] args) {
// 对于HashMap,需要额外的同步机制来确保线程安全
// synchronized (hashMap) {
// hashMap.put(1, 1);
// }
// Hashtable自带同步机制,无需额外处理
hashtable.put(1, 1);
}
}
分析
-
父类与接口实现:
HashMap
继承自AbstractMap
,而Hashtable
继承自Dictionary
。尽管它们的父类不同,但两者都实现了Map
、Cloneable
和Serializable
接口。
-
提供的额外方法:
Hashtable
提供了elements()
和contains()
两个额外的方法。elements()
方法返回一个Enumeration
对象,用于遍历Hashtable
中的值。contains()
方法在Hashtable
中实际上与containsValue()
方法功能相同,但在HashMap
中并不存在该方法。
-
对null的支持:
HashMap
允许一个null键和多个null值。Hashtable
则不允许键或值为null。
-
线程安全性:
HashMap
是非线程安全的,适用于单线程环境。在多线程环境中使用时,需要额外的同步机制来确保线程安全。Hashtable
是线程安全的,其所有方法都是同步的,因此可以直接用于多线程环境中。然而,这种同步机制会导致性能下降。
-
性能:
- 由于
HashMap
没有同步开销,因此其性能通常高于Hashtable
。
- 由于
-
初始容量与扩充容量:
HashMap
的初始容量为16,当容量不足时,会扩充为原来的2倍。Hashtable
的初始容量为11,当容量不足时,会扩充为原来的2倍加1(例如,11->23->47)。
-
计算hash值的方法:
HashMap
使用自定义的hash()
方法来计算键的哈希值,该方法会对键的hashCode()
进行进一步处理以减少哈希冲突。Hashtable
则直接使用键的hashCode()
作为哈希值。
综上所述,HashMap
和Hashtable
在多个维度上存在显著差异。对于需要线程安全且性能要求不高的场景,可以选择Hashtable
;对于性能要求高且能够自己处理线程安全的场景,则更推荐使用HashMap
。如果需要既线程安全又高性能的解决方案,可以考虑使用ConcurrentHashMap
。