Java 中的HashMap
和Hashtable
有几点不同:
Hashtable
是同步的 ,而HashMap
则不是。这使得HashMap
更适合非线程应用程序,因为非同步对象通常比同步对象执行得更好。
Hashtable
不允许使用null
键或值。 HashMap
允许一个null
键和任意数量的null
值。
HashMap 的子类之一是LinkedHashMap
,因此如果您想要可预测的迭代顺序(默认情况下是插入顺序),您可以轻松地为LinkedHashMap
换出HashMap
。如果您使用Hashtable
这将不那么容易。
由于同步对您来说不是问题,我建议使用HashMap
。如果同步成为问题,您还可以查看ConcurrentHashMap
。
请注意,许多答案表明 Hashtable 已同步。 在实践中,这很少给你买。访问器 / mutator 方法上的同步将阻止两个线程同时添加或从地图中删除,但在现实世界中,您经常需要额外的同步。
一个非常常见的习语是 “检查然后放” - 即在 Map 中查找条目,如果它尚不存在则添加它。无论您使用 Hashtable 还是 HashMap,这都不是原子操作。
可以通过以下方式获得等效同步的 HashMap:
Collections.synchronizedMap(myMap);
但要正确实现此逻辑,您需要额外的表单同步 :
synchronized(myMap) {
if (!myMap.containsKey("tomato"))
myMap.put("tomato", "red");
}
即使迭代 Hashtable 的条目(或 Collections.synchronizedMap 获得的 HashMap)也不是线程安全的,除非您还通过其他同步保护 Map 不被修改。
ConcurrentMap接口的实现(例如ConcurrentHashMap )通过包含线程安全的 check-then-act 语义来解决其中的一些问题,例如:
ConcurrentMap.putIfAbsent(key, value);
Hashtable
被视为遗留代码。有没有什么关于Hashtable
不能用做HashMap
或派生HashMap
,因此对于新的代码,我看不出有任何理由要回Hashtable
。