ChatGPT解决这个技术问题 Extra ChatGPT

Java中的HashMap和Hashtable有什么区别?

Java 中的 HashMapHashtable 有什么区别?

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

HashTable 在 Java 1.7 中已过时,建议使用 ConcurrentMap 实现
@MissFiona 不,这里不需要 ConcurrentMap,因为问题说“非线程应用程序”意味着线程/并发不是问题。
@BasilBourque,是的,但我相信 MissFiona 的意思类似于 "HashTable 传统上只是因为它的部分线程保护而被选择。但这已被 ConcurrentHashMap 消除,所以它通常被认为是退休了。通常建议在 HashMapConcurrentHashMap 之间进行选择。” 我相信这是一个明智的评论,如果这是她的意思。
根据doi.org/10.48550/arXiv.1602.00984,Hashtable 在能耗和执行时间方面都比 HashMap 更高效。

J
Josh Brown

Java 中的 HashMapHashtable 有几个区别:

Hashtable 是同步的,而 HashMap 不是。这使得 HashMap 更适合非线程应用程序,因为非同步对象通常比同步对象执行得更好。 Hashtable 不允许空键或空值。 HashMap 允许一个空键和任意数量的空值。 HashMap 的子类之一是 LinkedHashMap,因此如果您想要可预测的迭代顺序(默认为插入顺序),您可以轻松地将 HashMap 换成 LinkedHashMap。如果您使用 Hashtable,这将不会那么容易。

由于同步对您来说不是问题,因此我建议您使用 HashMap。如果同步成为问题,您还可以查看 ConcurrentHashMap


如果要使 HashMap 线程安全,请使用 Collections.synchronizedMap()
我还要评论说,Hashtable 中对线程安全的幼稚方法(“同步每个方法应该解决任何并发问题!”)使得线程应用程序非常更糟糕。您最好在外部同步 HashMap(并考虑后果),或使用 ConcurrentMap 实现(并利用其扩展 API 实现并发)。底线:使用 Hashtable 的唯一原因是旧版 API(约 1996 年)需要它时。
HashMap 为程序员在实际使用时编写线程安全代码提供了灵活性。我很少需要像 ConcurrentHashMap 或 HashTable 这样的线程安全集合。我需要的是同步块中的某些函数集或某些语句是线程安全的。
Hashtable 已过时,我们将 HashMap 用于非线程安全环境。如果您需要线程安全,则可以使用 Collections.synchronizedMap() 或使用比哈希表更有效的 ConcurrentHashMap。
它已经过时但没有被弃用,我想知道为什么会这样。我猜想删除这个类(和 Vector 出于同样的原因)会破坏太多现有的代码,并且使用 @Deprecated 进行注释将意味着删除代码的意图,这显然不存在。
G
Godfather

请注意,许多答案都表明 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)通过包含 线程安全的 check-then-act 语义解决了其中的一些问题,例如:

ConcurrentMap.putIfAbsent(key, value);

另请注意,如果修改了 HashMap,则指向它的迭代器将变为无效。
那么 synchronized(myMap) {...} 和 ConcurrentHashMap 在线程安全方面有什么区别吗?
在 JVM 开发团队中工作多年,我可以说 Hashtable 的内部同步至少对于在客户编写狡猾的并发代码时正确地指出客户的代码很有用。当原因是并发修改时,我们收到了一些关于 HashMap 内部失败的投诉(因此“显然”是一个 JDK/JVM 错误)。
Collections.synchronizedMap 的实现包括一个同步的 putIfAbsent,所以你不需要自己使用 containsKey/put。
k
kryger

Hashtable 被视为遗留代码。 Hashtable 没有什么是不能使用 HashMapHashMap 派生的,所以对于新代码,我看不出有任何理由回到 Hashtable


来自 Hashtable javadoc(已添加重点):“从 Java 2 平台 v1.2 开始,该类被改进为实现 Map 接口,使其成为 Java 集合框架的成员。”但是,您是对的,它是遗留代码。使用 Collections.synchronizedMap(HashMap) 可以更有效地获得同步的所有好处。 (类似于 Vector 是 Collections.synchronizedList(ArrayList) 的旧版本。)
@aberrant80:不幸的是,您在这两者之间别无选择,并且在为 J2ME 编程时必须使用 Hashtable ......
同意“哈希表被视为遗留代码”。如果你需要并发,你应该使用 ConcurentHashMap。
G
Godfather

这个问题经常在面试中被问到,以检查候选人是否理解集合类的正确用法以及是否知道可用的替代解决方案。

HashMap 类与 Hashtable 大致等价,不同之处在于它是非同步的并且允许空值。 (HashMap 允许空值作为键和值,而 Hashtable 不允许空值)。 HashMap 不保证地图的顺序会随着时间的推移保持不变。 HashMap 是非同步的,而 Hashtable 是同步的。 HashMap 中的迭代器是故障安全的,而 Hashtable 的枚举器则不是,如果任何其他线程通过添加或删除除 Iterator 自己的 remove() 方法之外的任何元素在结构上修改映射,则抛出 ConcurrentModificationException。但这不是保证行为,JVM 会尽最大努力来完成。

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

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

HashMap 可以通过

Map m = Collections.synchronizeMap(hashMap);

Map 提供 Collection 视图,而不是通过 Enumeration 对象直接支持迭代。集合视图极大地增强了界面的表现力,这将在本节后面讨论。 Map 允许您迭代键、值或键值对; Hashtable 不提供第三个选项。 Map 提供了一种在迭代过程中删除条目的安全方法; Hashtable 没有。最后,Map 修复了 Hashtable 界面中的一个小缺陷。 Hashtable 有一个名为 contains 的方法,如果 Hashtable 包含给定值,则该方法返回 true。鉴于其名称,如果 Hashtable 包含给定键,您会期望此方法返回 true,因为该键是 Hashtable 的主要访问机制。 Map 接口通过重命名方法 containsValue 消除了这种混淆来源。此外,这提高了界面的一致性 - containsValuecontainsKey 平行。

地图界面


1) HashMap 的迭代器不是故障安全的。他们是快速失败的。这两个术语之间的含义存在巨大差异。 2) HashMap 上没有 set 操作。 3) 如果之前有更改,put(...) 操作不会抛出 IllegalArgumentException。 4) 如果您更改映射,HashMap also 的快速失败行为会发生。 5) 保证快速失败的行为。 (如果您进行并发修改,则不能保证 HashTable 的行为。实际行为是......不可预测的。)
6) Hashtable 也不保证地图元素的顺序会随着时间的推移保持稳定。 (您可能将 HashtableLinkedHashMap 混淆了。)
还有其他人真的担心这些天的学生会错误地认为获得集合的“同步版本”意味着您不必在外部同步复合操作吗?我最喜欢的例子是 thing.set(thing.get() + 1);,它经常让新手感到惊讶,因为它完全不受保护,特别是如果 get()set() 是同步方法。他们中的许多人都在期待魔法。
Re 4:ConcurrentModificationException 与线程无关。这是关于保留一个迭代器并修改可能在同一个线程中发生的原始集合。
A
Apocalisp

HashMapMap 接口的实现,它使用哈希码来索引数组。 Hashtable:嗨,1998 年打来的电话。他们希望他们的收藏 API 回来。

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


这实际上是有道理的。 ConcurrentHashMaps 为您提供同步的自由,并且调试更容易。
P
Pratik Khadloya

请记住,在引入 Java 集合框架 (JCF) 之前,HashTable 是遗留类,后来经过改进以实现 Map 接口。 VectorStack 也是如此。

因此,在新代码中始终远离它们,因为正如其他人所指出的那样,JCF 中总是有更好的选择。

这是您会发现有用的 Java collection cheat sheet。请注意,灰色块包含遗留类 HashTable、Vector 和 Stack。

https://i.stack.imgur.com/PyflH.png


s
sanjeevRm

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

HashMapHashtable 都用于以键值形式存储数据。两者都使用散列技术来存储唯一键。但是下面给出的 HashMap 和 Hashtable 类之间存在许多差异。

哈希映射

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

哈希表

哈希表是同步的。它是线程安全的,可以与许多线程共享。 Hashtable 不允许空键或值。 Hashtable 是一个遗留类。哈希表很慢。 Hashtable 是内部同步的,不能不同步。 Hashtable 由 Enumerator 和 Iterator 遍历。 Hashtable 中的枚举器不是快速失败的。 Hashtable 继承 Dictionary 类。

进一步阅读What is difference between HashMap and Hashtable in Java?

https://i.stack.imgur.com/sDoih.png


为什么说~“Hashtable 是一个遗留类”?这方面的支持文件在哪里。
维护 HashMap 比 TreeMap 成本高。因为 HashMap 创建了不必要的额外存储桶。
LinkedHashMap 具有条目的双向链接列表,而不是存储桶。存储桶可通过数组索引访问,无需链接。
Pereira 等人 2016 年的一项研究。发现 Hashtable 对于大多数方法都比 HashMap 快,尤其是对于 containsKey、get、put 和 remove (arXiv:1602.00984)。因此,您声称“HashMap 很快”和“Hastable 很慢”很可能是错误的。
Y
Yousha Aleayoub

看看这张图表。它提供了不同数据结构以及 HashMapHashtable 之间的比较。比较准确、清晰且易于理解。

Java Collection Matrix


m
matt b

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

另请注意,Hashtable 扩展了 Dictionary 类,作为 Javadocs 状态,已过时并已被 Map 接口取代。


n
nbro

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


K
Koray Tugay

Hashtable 是同步的,而 HashMap 不是。这使得 HashtableHashmap 慢。

对于单线程应用程序,请使用 HashMap,因为它们在功能方面是相同的。


N
Neerja

hashtable 和 hashmap 之间的另一个关键区别是 HashMap 中的 Iterator 是快速失败的,而 Hashtable 的枚举器不是,并且如果任何其他线程通过添加或删除除 Iterator 自己的 remove() 方法之外的任何元素在结构上修改映射,则抛出 ConcurrentModificationException。但这不是保证行为,JVM 会尽最大努力完成。”

我的来源:http://javarevisited.blogspot.com/2010/10/difference-between-hashmap-and.html


C
Community

除了这里已经提到的所有其他重要方面之外,Collections API(例如 Map 接口)一直在修改以符合 Java 规范的“最新和最伟大”的补充。

例如,比较 Java 5 Map 迭代:

for (Elem elem : map.keys()) {
  elem.doSth();
}

与旧的 Hashtable 方法相比:

for (Enumeration en = htable.keys(); en.hasMoreElements(); ) {
  Elem elem = (Elem) en.nextElement();
  elem.doSth();
}

在 Java 1.8 中,我们还被承诺能够像在良好的旧脚本语言中一样构造和访问 HashMap:

Map<String,Integer> map = { "orange" : 12, "apples" : 15 };
map["apples"];

更新:不,他们不会登陆 1.8... :(

Are Project Coin's collection enhancements going to be in JDK8?


“新方式”也适用于 Hashtable(因为它还实现了 map 接口)。
准确地说,Hashtable 既不实现 Map 也不实现 Iterable(这是“新”foreach 语法所必需的)。但是,Hashtable.keySet() 返回确实允许该语法的 Set
更新:嗯,它确实实际上实现了 Map...很高兴在这么多年的无知之后得到纠正
a
alain.janinm

HashTable 是同步的,如果你在单线程中使用它,你可以使用 HashMap,它是一个非同步版本。未同步的对象通常性能更高一些。顺便说一句,如果多个线程同时访问一个HashMap,并且至少有一个线程在结构上修改了map,那么它必须在外部同步。您可以使用以下方法将未同步的地图包装在同步地图中: Map m = Collections.synchronizedMap(new HashMap(...));

HashTable 只能包含非空对象作为键或值。 HashMap 可以包含一个空键和空值。

Map 返回的迭代器是快速失败的,如果在创建迭代器后的任何时间对映射进行结构修改,除了通过迭代器自己的 remove 方法之外的任何方式,迭代器都会抛出 ConcurrentModificationException。因此,面对并发修改,迭代器快速而干净地失败,而不是在未来不确定的时间冒任意的、非确定性的行为。而 Hashtable 的键和元素方法返回的枚举不是快速失败的。

HashTable 和 HashMap 是 Java Collections Framework 的成员(从 Java 2 平台 v1.2 开始,HashTable 被改造以实现 Map 接口)。

HashTable 被认为是遗留代码,如果需要线程安全的高并发实现,文档建议使用 ConcurrentHashMap 代替 Hashtable。

HashMap 不保证返回元素的顺序。对于 HashTable 我想它是相同的,但我不完全确定,我没有找到明确说明这一点的资源。


S
SkyWalker

HashMapHashtable 在算法上也存在显着差异。以前没有人提到过这一点,所以这就是我提出它的原因。 HashMap 将构建一个大小为 2 次方的哈希表,动态增加它,使您在任何存储桶中最多有大约 8 个元素(碰撞),并且对于一般元素类型会很好地搅拌元素。但是,如果您知道自己在做什么,Hashtable 实现可以更好更精细地控制散列,也就是说,您可以使用最接近您的值域大小的素数来修复表大小,这将导致比 HashMap 更好的性能即在某些情况下更少的碰撞。

与此问题中广泛讨论的明显差异不同,我将 Hashtable 视为“手动驾驶”汽车,您可以更好地控制散列,而 HashMap 作为“自动驾驶”对应物,通常会表现良好。


p
pkaeding

根据信息 here,我建议使用 HashMap。我认为最大的优势是 Java 会阻止您在迭代它时对其进行修改,除非您通过迭代器进行修改。


我很确定它会在修改基础集合之前抛出 ConncurrentModificationException,尽管我可能是错的。
它将尝试检测并发修改并抛出异常。但是如果你用线程做任何事情,它就不能做出任何承诺。任何事情都可能发生,包括 breakage
C
Community

Collection(有时称为容器)只是将多个元素组合成一个单元的对象。 Collection 用于存储、检索、操作和交流聚合数据。集合框架W 是用于表示和操作集合的统一架构。

HashMap JDK1.2 和 Hashtable JDK1.0 都用于表示一组以 <Key, Value> 对表示的对象。每个 <Key, Value> 对称为 Entry 对象。条目集合由 HashMapHashtable 的对象引用。集合中的键必须是唯一的或独特的。 [因为它们用于检索特定键的映射值。集合中的值可以重复。]

« 超类、遗产和集合框架成员

Hashtable 是 JDK1.0 中引入的遗留类,它是 Dictionary 类的子类。从 JDK1.2 Hashtable 被重新设计以实现 Map interface 以使其成为集合框架的成员。 HashMap 是 Java 集合框架的成员,从它在 JDK1.2 中的介绍开始。 HashMap 是 AbstractMap 类的子类。

public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable { ... }

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { ... }

« 初始容量和负载系数

容量是哈希表中的桶数,初始容量只是哈希表创建时的容量。请注意,哈希表是开放的:对于“hash collision”,单个存储桶存储多个条目,必须按顺序搜索。负载因子是哈希表在其容量自动增加之前允许达到的程度的度量。

HashMap 使用默认初始容量 (16) 和默认加载因子 (0.75) 构造一个空哈希表。其中 Hashtable 构造具有默认初始容量 (11) 和负载因子/填充率 (0.75) 的空哈希表。

https://i.stack.imgur.com/AerdR.png

« 哈希冲突情况下的结构修改

HashMapHashtable 在哈希冲突的情况下,它们将映射条目存储在链表中。 从 Java8 到 HashMap 如果哈希桶增长超过某个阈值,该桶将从 linked list of entries to a balanced tree 切换。它将最坏情况的性能从 O(n) 提高到 O(log n)。将列表转换为二叉树时,哈希码用作分支变量。如果同一个桶中有两个不同的哈希码,一个被认为更大,在树的右边,另一个在左边。但是当两个哈希码相等时,HashMap 假定键是可比较的,并比较键以确定方向,以便可以保持某种顺序。制作 HashMap comparable 的键是一个很好的做法。在添加条目时,如果桶大小达到 TREEIFY_THRESHOLD = 8,则将条目链表转换为平衡树,在删除小于 TREEIFY_THRESHOLD 且最多 UNTREEIFY_THRESHOLD = 6 的条目时,会将平衡树重新转换为条目链表。 Java 8 SRCstackpost

« 集合视图迭代,Fail-Fast 和 Fail-Safe

    +--------------------+-----------+-------------+
    |                    | Iterator  | Enumeration |
    +--------------------+-----------+-------------+
    | Hashtable          | fail-fast |    safe     |
    +--------------------+-----------+-------------+
    | HashMap            | fail-fast | fail-fast   |
    +--------------------+-----------+-------------+
    | ConcurrentHashMap  |   safe    |   safe      |
    +--------------------+-----------+-------------+

Iterator 本质上是快速失败的。即,如果在迭代时修改了集合而不是它自己的 remove() 方法,它会抛出 ConcurrentModificationException。其中 Enumeration 本质上是故障安全的。如果在迭代时修改了集合,它不会抛出任何异常。

根据 Java API Docs,Iterator 总是优于 Enumeration。

注意:枚举接口的功能与迭代器接口相同。此外,Iterator 添加了一个可选的删除操作,并且具有更短的方法名称。新的实现应该考虑使用迭代器而不是枚举。

Java 5 introduced ConcurrentMap Interface 中:ConcurrentHashMap - 由哈希表支持的高度并发、高性能 ConcurrentMap 实现。此实现在执行检索时从不阻塞,并允许客户端选择更新的并发级别。它旨在替代 Hashtable:除了实现 ConcurrentMap,它还支持 Hashtable 特有的所有“旧”方法。

每个 HashMapEntrys 值都是可变的,从而确保竞争修改和后续读取的细粒度一致性;每次读取都反映了最近完成的更新

迭代器和枚举是故障安全的 - 反映自迭代器/枚举创建以来某个时刻的状态;这允许以降低一致性为代价同时读取和修改。它们不会抛出 ConcurrentModificationException。但是,迭代器被设计为一次只能由一个线程使用。

与 Hashtable 类似,但与 HashMap 不同,此类不允许将 null 用作键或值。

public static void main(String[] args) {

    //HashMap<String, Integer> hash = new HashMap<String, Integer>();
    Hashtable<String, Integer> hash = new Hashtable<String, Integer>();
    //ConcurrentHashMap<String, Integer> hash = new ConcurrentHashMap<>();
    
    new Thread() {
        @Override public void run() {
            try {
                for (int i = 10; i < 20; i++) {
                    sleepThread(1);
                    System.out.println("T1 :- Key"+i);
                    hash.put("Key"+i, i);
                }
                System.out.println( System.identityHashCode( hash ) );
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }
    }.start();
    new Thread() {
        @Override public void run() {
            try {
                sleepThread(5);
                // ConcurrentHashMap  traverse using Iterator, Enumeration is Fail-Safe.
                
                // Hashtable traverse using Enumeration is Fail-Safe, Iterator is Fail-Fast.
                for (Enumeration<String> e = hash.keys(); e.hasMoreElements(); ) {
                    sleepThread(1);
                    System.out.println("T2 : "+ e.nextElement());
                }
                
                // HashMap traverse using Iterator, Enumeration is Fail-Fast.
                /*
                for (Iterator< Entry<String, Integer> > it = hash.entrySet().iterator(); it.hasNext(); ) {
                    sleepThread(1);
                    System.out.println("T2 : "+ it.next());
                    // ConcurrentModificationException at java.util.Hashtable$Enumerator.next
                }
                */
                
                /*
                Set< Entry<String, Integer> > entrySet = hash.entrySet();
                Iterator< Entry<String, Integer> > it = entrySet.iterator();
                Enumeration<Entry<String, Integer>> entryEnumeration = Collections.enumeration( entrySet );
                while( entryEnumeration.hasMoreElements() ) {
                    sleepThread(1);
                    Entry<String, Integer> nextElement = entryEnumeration.nextElement();
                    System.out.println("T2 : "+ nextElement.getKey() +" : "+ nextElement.getValue() );
                    //java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode
                    //                                          at java.util.HashMap$EntryIterator.next
                    //                                          at java.util.Collections$3.nextElement
                }
                */
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }
    }.start();
    
    Map<String, String> unmodifiableMap = Collections.unmodifiableMap( map );
    try {
        unmodifiableMap.put("key4", "unmodifiableMap");
    } catch (java.lang.UnsupportedOperationException e) {
        System.err.println("UnsupportedOperationException : "+ e.getMessage() );
    }
}
static void sleepThread( int sec ) {
    try {
        Thread.sleep( 1000 * sec );
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

« 空键和空值

HashMap 最多允许一个空键和任意数量的空值。其中 Hashtable 甚至不允许单个空键和空值,如果键或值为空,则抛出 NullPointerException。 Example

« 同步,线程安全

Hashtable 在内部同步。因此,在多线程应用程序中使用 Hashtable 是非常安全的。其中 HashMap 未在内部同步。因此,在没有外部同步的多线程应用程序中使用 HashMap 是不安全的。您可以使用 Collections.synchronizedMap() 方法在外部同步 HashMap

“ 表现

由于 Hashtable 是内部同步的,因此 HashtableHashMap 稍慢。

@看

红黑树是一种自平衡二叉搜索树

Java 8 中 HashMap 的性能改进


T
Tim Howland

对于线程应用程序,您通常可以使用 ConcurrentHashMap - 取决于您的性能要求。


J
Jared Burrows

1.HashmapHashTable 都存储键和值。

2.Hashmap可以将一个密钥存储为nullHashtable 无法存储 null

3.HashMap 未同步,但 Hashtable 已同步。

4.HashMap可以与Collection.SyncronizedMap(map)同步

Map hashmap = new HashMap();

Map map = Collections.SyncronizedMap(hashmap);

K
Kostas Kryptos

除了已经提到的差异之外,需要注意的是,从 Java 8 开始,HashMap 将每个桶中使用的 Nodes(链表)动态替换为 TreeNodes(红黑树),因此即使存在高哈希冲突,最坏的情况搜索时

HashtableHashMap Vs O(n) 的 O(log(n))。

*上述改进尚未应用于 Hashtable,而仅应用于 HashMapLinkedHashMapConcurrentHashMap

仅供参考,目前,

TREEIFY_THRESHOLD = 8 :如果一个桶包含超过 8 个节点,则将链表转换为平衡树。

UNTREEIFY_THRESHOLD = 6 :当存储桶变得太小(由于删除或调整大小)时,树将转换回链表。


当然,这棵树只有在密钥的哈希码实际上不同并且恰好落入同一个桶时才有帮助,而不是当您实际上获得许多具有相同哈希码的密钥时。
B
Brad Larson

HashTable 和 HashMap 有 5 个基本区别。

Maps 允许您迭代和检索键、值以及键值对,而 HashTable 不具备所有这些功能。在 Hashtable 中有一个函数 contains(),使用起来非常混乱。因为 contains 的意思略有偏差。是指包含键还是包含值?很难理解。同样,在 Maps 中,我们有 ContainsKey() 和 ContainsValue() 函数,它们非常容易理解。在 hashmap 中,您可以在迭代时安全地删除元素。因为在哈希表中是不可能的。 HashTables 默认是同步的,所以它可以很容易地与多个线程一起使用。 HashMaps 默认是不同步的,所以只能在单线程中使用。但是您仍然可以使用 Collections util 类的 synchronizedMap(Map m) 函数将 HashMap 转换为同步。 HashTable 不允许空键或空值。 HashMap 允许一个空键和多个空值。


C
Community

我的小贡献:

Hashtable 和 HashMap 之间的第一个也是最显着的区别是,HashMap 不是线程安全的,而 Hashtable 是线程安全的集合。 Hashtable 和 HashMap 之间的第二个重要区别是性能,因为 HashMap 不同步,它的性能比 Hashtable 更好。 Hashtable 与 HashMap 的第三个区别是 Hashtable 是过时的类,您应该使用 ConcurrentHashMap 代替 Java 中的 Hashtable。


P
Pang

HashMap:它是 java.util 包中的一个类,用于以键值格式存储元素。

Hashtable:它是一个在集合框架中被识别的遗留类。


I
Ihor Patsian

Hashtable 是同步的,而 HashMap 不是。另一个区别是 HashMap 中的迭代器是故障安全的,而 Hashtable 的枚举器则不是。如果您在迭代时更改地图,您就会知道。 HashMap 允许其中包含空值,而 Hashtable 不允许。


HashMap 迭代器是快速失败的而不是失败安全的。这就是为什么我们有允许在迭代时修改的 ConcurrentHashMap。检查这篇文章journaldev.com/122/…
j
jontejj

HashTable 是 jdk 中不应再使用的遗留类。用 ConcurrentHashMap 替换它的用法。如果您不需要线程安全,请使用 HashMap,它不是 threadsafe,但速度更快且使用更少的内存。


因为当时我认为其他答案并没有解雇 HashTable 而是解释说它是线程安全的。事实是,一旦您在代码中看到 HashTable,就应该将其替换为 ConcurrentHashMap 而不会跳过一个节拍。如果线程安全不是问题,那么可以使用 HashMap 来稍微提高性能。
P
Pawan Patil

HashMap 和 HashTable

关于 HashMap 和 HashTable 的一些要点。请阅读以下详细信息。

1) Hashtable 和 Hashmap 实现 java.util.Map 接口 2) Hashmap 和 Hashtable 都是基于散列的集合。并致力于散列。所以这些是HashMap和HashTable的相似之处。

HashMap 和 HashTable 有什么区别?

1)第一个区别是 HashMap 不是线程安全的,而 HashTable 是 ThreadSafe 2)HashMap 在性能方面更好,因为它不是线程安全的。而 Hashtable 性能并不好,因为它是线程安全的。所以多个线程不能同时访问Hashtable。


投反对票,因为这个答案在某些方面是不正确的。 Hashtable 没有实现 Map 接口,只是扩展了 Dictionary 类,这个类已经过时了。
@IoannisSermetziadis 至少在 Java 6 API 中,Hashtable 还实现了 Map 接口。
D
DeC

HashMap 和 Hashtable 都用于以 key 和 value 的形式存储数据。两者都使用散列技术来存储唯一键。但是下面给出的 HashMap 和 Hashtable 类之间存在许多差异。

https://i.stack.imgur.com/mLpKn.png


m
manojgolty

Hashtable:

Hashtable 是一种保留键值对值的数据结构。它不允许键和值都为 null。如果添加 null 值,您将获得 NullPointerException。它是同步的。所以它伴随着它的成本。在特定时间只有一个线程可以访问 HashTable

例子 :

import java.util.Map;
import java.util.Hashtable;

public class TestClass {

    public static void main(String args[ ]) {
    Map<Integer,String> states= new Hashtable<Integer,String>();
    states.put(1, "INDIA");
    states.put(2, "USA");

    states.put(3, null);    //will throw NullPointerEcxeption at runtime

    System.out.println(states.get(1));
    System.out.println(states.get(2));
//  System.out.println(states.get(3));

    }
}

哈希映射:

HashMap 类似于 Hashtable,但它也接受键值对。它允许键和值都为 null。它的性能优于HashTable,因为它是unsynchronized

例子:

import java.util.HashMap;
import java.util.Map;

public class TestClass {

    public static void main(String args[ ]) {
    Map<Integer,String> states = new HashMap<Integer,String>();
    states.put(1, "INDIA");
    states.put(2, "USA");

    states.put(3, null);    // Okay
    states.put(null,"UK");

    System.out.println(states.get(1));
    System.out.println(states.get(2));
    System.out.println(states.get(3));

    }
}

B
BalusC

古老而经典的话题,只想添加这个有用的博客来解释这一点:

http://blog.manishchhabra.com/2012/08/the-5-main-differences-betwen-hashmap-and-hashtable/

Manish Chhabra 的博客

HashMap 和 Hashtable 之间的 5 个主要区别 HashMap 和 Hashtable 都实现了 java.util.Map 接口,但是 Java 开发人员必须了解一些区别才能编写更高效的代码。从 Java 2 平台 v1.2 开始,Hashtable 类被改进为实现 Map 接口,使其成为 Java Collections Framework 的成员。 HashMap 和 Hashtable 之间的主要区别之一是 HashMap 是非同步的,而 Hashtable 是同步的,这意味着 Hashtable 是线程安全的,可以在多个线程之间共享,但 HashMap 不能在没有适当同步的情况下在多个线程之间共享。 Java 5 引入了 ConcurrentHashMap,它是 Hashtable 的替代品,提供了比 Java 中的 Hashtable 更好的可扩展性。同步意味着在一个时间点只有一个线程可以修改一个哈希表。基本上,这意味着任何线程在对哈希表执行更新之前都必须获取对象上的锁,而其他线程将等待锁被释放。 HashMap 类大致相当于 Hashtable,除了它允许空值。 (HashMap 允许空值作为键和值,而 Hashtable 不允许空值)。 HashMap 与 Hashtable 之间的第三个重要区别是 HashMap 中的 Iterator 是一个快速失败的迭代器,而 Hashtable 的枚举器不是,并且如果任何其他线程通过添加或删除除 Iterator 自己的 remove( ) 方法。但这不是保证行为,JVM 会尽最大努力来完成。这也是 Java 中 Enumeration 和 Iterator 的一个重要区别。 Hashtable 和 HashMap 之间更显着的区别是,由于线程安全和同步,如果在单线程环境中使用,Hashtable 比 HashMap 慢得多。因此,如果您不需要同步并且 HashMap 仅由一个线程使用,它会在 Java 中执行 Hashtable。 HashMap 不保证地图的顺序会随着时间的推移保持不变。注意 HashMap 可以通过 Map m = Collections.synchronizedMap(hashMap); 来同步。总而言之,Java 中的 Hashtable 和 HashMap 之间存在显着差异,例如线程安全和速度,基于此,如果您绝对需要线程安全,则仅使用 Hashtable,如果您正在运行 Java 5,请考虑在 Java 中使用 ConcurrentHashMap。


ConcurrentHashMap 不是读同步的,而 Hashtable 是。因此,如果您有大量的读取操作与写入同时发生,那么如果您关心数据完整性,哈希表会更好地为您服务。
a
amitguptageek

同步或线程安全:

Hash Map 不是同步的,因此它不是线程安全的,并且如果没有适当的同步块,它就不能在多个线程之间共享,而 Hashtable 是同步的,因此它是线程安全的。

空键和空值:

HashMap 允许一个空键和任意数量的空值。Hashtable 不允许空键或空值。

迭代值:

HashMap 中的迭代器是一个快速失败的迭代器,而 Hashtable 的枚举器不是,如果任何其他线程通过添加或删除除 Iterator 自己的 remove() 方法之外的任何元素在结构上修改映射,则抛出 ConcurrentModificationException。

超类和遗产:

HashMap 是 AbstractMap 类的子类,而 Hashtable 是 Dictionary 类的子类。

表现 :

由于 HashMap 不同步,因此它比 Hashtable 更快。

有关 Java 集合的示例、面试问题和测验,请参阅 http://modernpathshala.com/Article/1020/difference-between-hashmap-and-hashtable-in-java