HashMap 和 Hashtable 之间的区别?

Java 中的HashMapHashtable有什么区别?

对于非线程应用程序,哪个更有效?

答案

Java 中的HashMapHashtable之间有一些区别:

  1. Hashtable同步的 ,而HashMap不是。这使HashMap更适合非线程应用程序,因为非同步对象通常比同步对象表现更好。

  2. Hashtable不允许使用null键或null值。 HashMap允许一个null键和任意数量的null值。

  3. HashMap 的子类之一是LinkedHashMap ,因此,如果您需要可预测的迭代顺序(默认情况下为插入顺序),则可以轻松地将HashMap换成LinkedHashMap 。如果您正在使用Hashtable这将不会那么容易。

由于同步对您来说不是问题,所以我建议HashMap 。如果同步成为问题,您也可以查看ConcurrentHashMap

请注意,很多答案都说明 Hashtable 已同步。 实际上,这几乎买不到您。同步在访问器 / 更改器方法上将停止同时从映射中添加或删除两个线程,但是在现实世界中,您经常需要进行额外的同步。

一个非常常见的习惯用法是 “先检查后放入”,即在Map查找条目,如果尚不存在,则将其添加。无论您使用Hashtable还是HashMap这都不是原子操作。

可以通过以下方式获取等效同步的HashMap

Collections.synchronizedMap(myMap);

但是要正确实现此逻辑,您需要对表单进行额外的同步

synchronized(myMap) {
    if (!myMap.containsKey("tomato"))
        myMap.put("tomato", "red");
}

甚至遍历Hashtable的条目(或由Collections.synchronizedMap获得的HashMap )也是线程安全的,除非您还防止通过附加同步来修改Map

ConcurrentMap接口的实现(例如ConcurrentHashMap )通过包含线程安全的 “先检查后行为” 语义来解决其中的一些问题,例如:

ConcurrentMap.putIfAbsent(key, value);

Hashtable被认为是遗留代码。没有什么有关的Hashtable不能用做HashMap或派生HashMap ,因此对于新的代码,我看不到回去的任何理由Hashtable

面试中经常会问这个问题,以检查应聘者是否理解收集类的正确用法,并了解可用的替代解决方案。

  1. HashMap类与Hashtable大致等效,除了它是不同步的并且允许为 null 之外。 ( HashMap允许将 null 值用作键和值,而Hashtable不允许null )。
  2. HashMap不保证地图的顺序会随着时间的推移保持不变。
  3. HashMap是不同步的,而Hashtable是同步的。
  4. HashMap Iterator 是故障安全的,而Hashtable的枚举器则不是,并且如果其他任何线程通过添加或删除Iterator自己的remove()方法之外的任何元素来结构性地修改映射,则抛出ConcurrentModificationException 。但这不是保证的行为,将由 JVM 尽力而为。

关于一些重要术语的注意事项:

  1. 同步意味着只有一个线程可以在某个时间点修改哈希表。基本上,这意味着在对Hashtable执行更新之前,任何线程都必须获取对象的锁,而其他线程将等待释放锁。
  2. 故障安全在迭代器的上下文中是相关的。如果在集合对象上创建了迭代器,并且其他某个线程试图 “结构化” 修改集合对象,则将引发并发修改异常。尽管其他线程可能不会调用set方法,因为它不会 “结构化” 地修改集合,因此可能会调用set方法。但是,如果在调用set之前对集合进行了结构性修改,则将抛出IllegalArgumentException
  3. 结构修改是指删除或插入可以有效改变地图结构的元素。

HashMap可以通过以下方式同步

Map m = Collections.synchronizeMap(hashMap);

Map 提供了 Collection 视图,而不是通过 Enumeration 对象直接支持迭代。集合视图极大地增强了接口的表达能力,如本节后面所述。 Map 允许您迭代键,值或键值对; Hashtable不提供第三个选项。 Map 提供了一种在迭代过程中删除条目的安全方法; Hashtable没有。最后,Map 修复了Hashtable界面中的一个小缺陷。 Hashtable有一个名为 contains 的方法,如果Hashtable包含给定值,则该方法返回 true。给定其名称,如果Hashtable包含给定键,则您希望此方法返回 true,因为该键是Hashtable的主要访问机制。 Map 接口通过重命名方法containsValue消除了这种混乱的根源。此外,这还改善了接口的一致性— containsValue并行containsKey

地图界面

HashMapMap接口的一种实现,它使用哈希码来索引数组。 Hashtable :您好,1998 年致电。他们想要他们的收藏 API。

认真地说,最好还是完全远离Hashtable 。对于单线程应用程序,您不需要额外的同步开销。对于高度并发的应用程序,偏执同步可能会导致饥饿,死锁或不必要的垃圾收集暂停。就像 Tim Howland 指出的那样,您可以改用ConcurrentHashMap

请记住,在引入 Java Collections Framework(JCF)之前, HashTable是旧类,后来又进行了改进以实现Map接口。 VectorStack

因此,由于其他人指出的, JCF 中总是有更好的替代方法,因此请始终远离新代码

这是Java 收集备忘单 ,您会发现它很有用。请注意,灰色块包含旧类 HashTable,Vector 和 Stack。

在此处输入图片说明

已经发布了许多好的答案。我要添加一些新观点并进行总结。

HashMapHashtable都用于存储键和值形式的数据 。两者都使用哈希技术来存储唯一密钥。但是,下面给出的 HashMap 和 Hashtable 类之间有许多区别。

哈希图

  1. HashMap不同步。它不是线程安全的,没有适当的同步代码就无法在许多线程之间共享。
  2. HashMap允许一个空键和多个空值。
  3. HashMap是 JDK 1.2 中引入的新类。
  4. HashMap很快。
  5. 我们可以通过调用以下代码使HashMap同步
    Map m = Collections.synchronizedMap(HashMap);
  6. HashMap被 Iterator 遍历。
  7. HashMap迭代器是快速失败的。
  8. HashMap继承 AbstractMap 类。

哈希表

  1. Hashtable已同步。它是线程安全的,可以与许多线程共享。
  2. Hashtable不允许任何空键或值。
  3. Hashtable是一个遗留类。
  4. Hashtable很慢。
  5. Hashtable在内部是同步的,不能不同步。
  6. Hashtable被 Enumerator 和 Iterator 遍历。
  7. Hashtable枚举器不是快速失败的。
  8. Hashtable继承 Dictionary 类。

进一步阅读Java 中的 HashMap 和 Hashtable 有什么区别?

在此处输入图片说明

除了 izb 所说的之外, HashMap允许空值,而Hashtable则不允许。

还请注意, Hashtable扩展了Dictionary类,正如Javadocs 所声明的那样,该类已过时,已由Map接口取代。

看一下这张图。它提供了HashMapHashtable以及不同数据结构之间的比较。这种比较是准确,清晰和易于理解的。

Java 集合矩阵

HashtableHashMap相似,并且具有相似的接口。建议您使用HashMap ,除非您需要支持旧版应用程序或需要同步,因为Hashtables方法已同步。因此,在您不是多线程的情况下, HashMaps是您的最佳选择。