繁体   English   中英

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

[英]What are the differences between a HashMap and a Hashtable in Java?

Java 中的HashMapHashtable有什么区别?

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

Java中HashMapHashtable有几个区别:

  1. Hashtablesynchronized ,而HashMap不是。 这使得HashMap更适合非线程应用程序,因为未同步的对象通常比同步的对象执行得更好。

  2. Hashtable不允许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 )通过包含线程安全的 check-then-act 语义解决了其中的一些问题,例如:

ConcurrentMap.putIfAbsent(key, value);

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

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

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

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

  1. 同步意味着只有一个线程可以在一个时间点修改哈希表。 基本上,这意味着在对Hashtable执行更新之前,任何线程都必须获取对象上的锁,而其他线程将等待释放锁。
  2. 故障安全在迭代器的上下文中是相关的。 如果在集合对象上创建了迭代器,并且某个其他线程尝试“结构化”修改集合对象,则会引发并发修改异常。 尽管其他线程可以调用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被迭代器遍历。
  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 有什么区别?

在此处输入图片说明

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

Java 集合矩阵

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

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

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

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

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

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

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

除了这里已经提到的所有其他重要方面之外,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 中登陆... :(

Project Coin 的收藏增强功能是否会出现在 JDK8 中?

  • HashTable是同步的,如果您在单线程中使用它,您可以使用HashMap ,这是一个非同步版本。 未同步的对象通常性能更高一些。 顺便说一下,如果多个线程并发访问一个HashMap,并且至少有一个线程在结构上修改了映射,则必须在外部进行同步。 您可以使用以下方法将未同步的地图包装在同步地图中:

     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 我猜它是一样的,但我不完全确定,我没有找到明确说明的资源。

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

除了这个问题中广泛讨论的明显差异之外,我将 Hashtable 视为“手动驱动”汽车,您可以更好地控制散列,而 HashMap 作为“自动驱动”对应物,通常性能良好。

根据这里的信息,我建议使用 HashMap。 我认为最大的优点是 Java 会阻止你在迭代时修改它,除非你通过迭代器来做。

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

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


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

Hashtable 是JDK1.0引入的遗留类,是Dictionary 类的子类。 JDK1.2重新设计Hashtable,实现Map接口,成为集合框架的成员。 HashMap 从它在JDK1.2引入开始就是 Java Collection Framework 的成员。 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) 的空哈希表。

哈希映射和哈希表

«发生哈希冲突时的结构修改

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

«集合视图迭代,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 添加了一个可选的删除操作,并具有较短的方法名称。 新的实现应该考虑使用 Iterator 而不是 Enumeration。

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

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

  • 迭代器和枚举是故障安全的——反映自迭代器/枚举创建以来某个时刻的状态; 这允许以降低一致性为代价的同时读取和修改。 它们不会抛出 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。 示例

«同步,线程安全

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

«性能

由于Hashtable是内部同步的,这使得HashtableHashMap稍慢。


@见

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

1. HashmapHashTable都存储 key 和 value。

2. Hashmap可以存储一个 key 为null Hashtable不能存储null

3、 HashMap不同步, Hashtable同步。

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

Map hashmap = new HashMap();

Map map = Collections.SyncronizedMap(hashmap);

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

O(log(n)) for HashMap Vs O(n) in Hashtable

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

仅供参考,目前,

  • TREEIFY_THRESHOLD = 8 :如果一个bucket包含8个以上的节点,则链表转化为平衡树。
  • UNTREEIFY_THRESHOLD = 6 :当桶变得太小(由于移除或调整大小)时,树将转换回链表。

HashTable 和 HashMaps 有 5 个基本区别。

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

我的小贡献:

  1. HashtableHashMap第一个也是最显着的区别是, HashMap不是线程安全的,而Hashtable是线程安全的集合。

  2. HashtableHashMap之间的第二个重要区别是性能,因为HashMap不是同步的,它比Hashtable性能更好。

  3. HashtableHashMap第三个区别是Hashtable是过时的类,您应该使用ConcurrentHashMap代替 Java 中的Hashtable

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

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

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

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

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:

哈希表是一种保留键值对值的数据结构。 它不允许键和值都为 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));

    }
}

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

在此处输入图片说明

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

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 集合框架的成员。

  1. HashMap 和 Hashtable 的主要区别之一是 HashMap 是非同步的,而 Hashtable 是同步的,这意味着 Hashtable 是线程安全的,可以在多个线程之间共享,但 HashMap 不能在没有适当同步的情况下在多个线程之间共享。 Java 5 引入了 ConcurrentHashMap,它是 Hashtable 的替代品,提供比 Java 中的 Hashtable 更好的可扩展性。同步意味着在一个时间点只有一个线程可以修改哈希表。 基本上,这意味着在对哈希表执行更新之前,任何线程都必须获取对象上的锁,而其他线程将等待释放锁。

  2. HashMap 类大致等同于 Hashtable,除了它允许空值。 (HashMap 允许空值作为键和值,而 Hashtable 不允许空值)。

  3. HashMap 与 Hashtable 之间的第三个显着区别是 HashMap 中的 Iterator 是一个快速失败的迭代器,而 Hashtable 的枚举器不是,如果任何其他线程通过添加或删除除迭代器自己的元素之外的任何元素在结构上修改映射,则抛出 ConcurrentModificationException ) 方法。 但这不是保证的行为,JVM 会尽最大努力完成。 这也是Java中Enumeration和Iterator的一个重要区别。

  4. Hashtable 和 HashMap 之间更显着的区别是,由于线程安全和同步,如果在单线程环境中使用,Hashtable 比 HashMap 慢得多。 因此,如果您不需要同步并且 HashMap 仅由一个线程使用,那么它在 Java 中执行 Hashtable。

  5. HashMap 不保证映射的顺序会随着时间的推移保持不变。

请注意,HashMap 可以通过以下方式同步

Map m = Collections.synchronizedMap(hashMap);

总而言之,Java 中的 Hashtable 和 HashMap 之间存在显着差异,例如线程安全和速度,并且仅在您绝对需要线程安全时才使用 Hashtable,如果您正在运行 Java 5,请考虑在 Java 中使用 ConcurrentHashMap。

HashMap是模拟的,因此可以在GWT client code使用,而Hashtable则不是。

HashMaps使您可以自由进行同步,调试更加轻松

由于Java中的Hashtable是Dictionary类的子类,由于Map接口的存在,现在已经过时,不再使用。 此外,对于实现 Map Interface 的类,您可以使用 Hashtable 执行任何操作。

同步或线程安全

哈希映射未同步,因此不安全,并且在没有适当的同步块的情况下无法在多个线程之间共享,而哈希表已同步,因此是线程安全的。

空键和空值

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

迭代值

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

超类和遗产

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

性能

由于HashMap不同步,因此与Hashtable相比,速度更快。

请参阅http://modernpathshala.com/Article/1020/difference-between-hashmap-and-hashtable-in-java中的示例以及与Java集合有关的访谈问题和测验

HashMap 是一个用于以键和值格式存储元素的类。它不是线程安全的。 因为它不是同步的。因为 Hashtable 是同步的。Hashmap 允许为空,但 hastable 不允许为空。

Hashtable 类是同步的,也就是说,它旨在供处理多线程或多线程进程的应用程序使用。 在应用程序到进程的经典情况下,同步类的效率较低,因此 Hashmap 类通常更快。 HashTable 类不接受 Null 值,无论是键还是值,而 HashMap 类允许单个键为 Null 并尽可能多地为 null。

Hashtable 是线程安全的,可以在应用程序中的多个线程之间共享。

另一方面,HashMap 不是同步的,如果没有额外的同步代码,就不能被多个线程访问。 我们可以使用Collections.synchronizedMap()来制作 HashMap 的线程安全版本。 我们也可以创建自定义锁定代码或使用 synchronized 关键字使代码成为线程安全的。

HashMap 不是同步的,因此它比 Hashtable 更快并且使用更少的内存。 通常,在单线程应用程序中,未同步的对象比同步的对象要快。

Hashtable 根本不允许 null。

我们应该将 HashMap 用于非同步或单线程应用程序。

从 JDK 1.8 开始,Hashtable 已被弃用。 然而,ConcurrentHashMap 是一个很好的 Hashtable 替代品。 我们应该考虑在具有多线程的应用程序中使用 ConcurrentHashMap。

HashMap 和 Hashtable 将键/值对存储在哈希表中。 使用 Hashtable 或 HashMap 时,我们指定一个用作键的对象以及要链接到该键的值。 然后对键进行散列,所得散列代码用作将值存储在表中的索引。 示例 Java 代码。

// A sample Java program to demonstrate HashMap and HashTable
import java.util.*;
import java.lang.*;
import java.io.*;
 
// Name of the class has to be "Main" only if the class is public
class Ideone
{
    public static void main(String args[])
    {
        // hashtable
        Hashtable<Integer,String> ht=new Hashtable<Integer,String>();
        ht.put(101," test");
        ht.put(101,"test1");
        ht.put(102,"test2");
        ht.put(103,"test3");
        System.out.println("-------------Hash table--------------");
        for (Map.Entry m:ht.entrySet()) {
            System.out.println(m.getKey()+" "+m.getValue());
        }
 
        // hashmap
        HashMap<Integer,String> hm=new HashMap<Integer,String>();
        hm.put(100,"test");
        hm.put(104,"test1"); 
        hm.put(101,"test2");
        hm.put(102,"test3");
        System.out.println("-----------Hash map-----------");
        for (Map.Entry m:hm.entrySet()) {
            System.out.println(m.getKey()+" "+m.getValue());
        }
    }
}

---- Hash table --- 103 test3 102 test2 101 test1
---- Hash map   --- 100 test 101 test2 102 test3 104 test1

哈希图与哈希表

  1. HashMap 是非同步的。 它不是线程安全的,如果没有适当的同步代码,就不能在许多线程之间共享,而 Hashtable 是同步的。 它是线程安全的,可以与多个线程共享。
  2. HashMap 允许一个空键和多个空值,而 Hashtable 不允许任何空键或值。
  3. 如果不需要线程同步,HashMap 通常优于 HashTable 为什么 HashTable 不允许 null 而 HashMap 呢? 要成功地从 HashTable 存储和检索对象,用作键的对象必须实现 hashCode 方法和 equals 方法。 由于 null 不是对象,因此无法实现这些方法。 HashMap 是对 Hashtable 的高级版本和改进。 HashMap 是后来创建的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM