Java中HashMap和Hashtable之间的区别是什么?
对于非线程应用程序,哪个更有效?
Java中HashMap和Hashtable之间的区别是什么?
对于非线程应用程序,哪个更有效?
当前回答
根据这里的信息,我建议使用HashMap。我认为最大的优点是,Java将防止您在迭代时修改它,除非您通过迭代器进行修改。
其他回答
哈希表:
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,但它也接受键值对。它允许键和值都为空。它的性能优于HashTable,因为它是非同步的。
例子:
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));
}
}
HashMap:它是java.util包中可用的类,用于以键和值格式存储元素。
Hashtable:它是一个在集合框架中被识别的遗留类。
根据这里的信息,我建议使用HashMap。我认为最大的优点是,Java将防止您在迭代时修改它,除非您通过迭代器进行修改。
集合(有时称为容器)只是将多个元素分组为单个单元的对象。集合用于存储、检索、操作和传递聚合数据。集合框架W是用于表示和操作集合的统一架构。
HashMap JDK1.2和Hashtable JDK1.0都用于表示一组对象,这些对象在<Key,Value>对中表示。每个<Key,Value>对都称为Entry对象。条目集合由HashMap和Hashtable的对象引用。集合中的键必须是唯一的或与众不同的。[因为它们用于检索特定键的映射值。集合中的值可以重复。]
«超级类、传统和收藏框架成员
Hashtable是JDK1.0中引入的一个遗留类,它是Dictionary类的一个子类。从JDK1.2哈希表被重新设计以实现Map接口,从而成为集合框架的成员。HashMap从JDK1.2引入之初就是Java集合框架的成员。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 { ... }
«初始容量和负载系数
容量是哈希表中桶的数量,初始容量只是创建哈希表时的容量。注意,哈希表是开放的:在“哈希冲突”的情况下,一个存储桶存储多个条目,这些条目必须按顺序搜索。负载因子是在哈希表的容量自动增加之前,允许哈希表达到多满的度量。
HashMap使用默认初始容量(16)和默认负载因子(0.75)构造一个空哈希表。Where as Hashtable使用默认初始能力(11)和负载因子/填充比(0.75)构建空哈希表。
«哈希冲突时的结构修改
HashMap,Hashtable在哈希冲突的情况下,它们将映射条目存储在链接列表中。从Java8 for HashMap中,如果哈希桶增长超过某个阈值,该桶将从条目链接列表切换到平衡树。这将最坏情况性能从O(n)提高到O(logn)。在将列表转换为二进制树时,哈希代码用作分支变量。如果同一个存储桶中有两个不同的哈希码,一个被认为更大,并位于树的右侧,另一个位于左侧。但是,当两个哈希码相等时,HashMap假设键是可比较的,并比较键以确定方向,以便保持某种顺序。使HashMap的键具有可比性是一个很好的做法。在添加条目时,如果存储桶大小达到TREEIFY_THRESHOLD=8,则将条目的链接列表转换为平衡树;在删除小于TREEIFY_THRESHOLD且最多为UNTREEIFY_THRESHOLD=6的条目时,将重新将平衡树转换为条目的链接表。Java 8 SRC,堆栈
«集合视图迭代、快速故障和安全故障
+--------------------+-----------+-------------+
| | Iterator | Enumeration |
+--------------------+-----------+-------------+
| Hashtable | fail-fast | safe |
+--------------------+-----------+-------------+
| HashMap | fail-fast | fail-fast |
+--------------------+-----------+-------------+
| ConcurrentHashMap | safe | safe |
+--------------------+-----------+-------------+
迭代器本质上是一种快速故障。即,如果在迭代而不是自己的remove()方法时修改了集合,则会抛出ConcurrentModificationException。其中作为枚举本质上是故障安全的。如果在迭代时修改了集合,则不会引发任何异常。
根据JavaAPI文档,迭代器总是优先于枚举。
注意:枚举接口的功能与迭代器接口重复。此外,Iterator添加了一个可选的移除操作,并且方法名称更短。新的实现应该考虑使用迭代器而不是枚举。
在Java5中引入了ConcurrentMap接口: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最多允许一个空键和任意数量的空值。如果as Hashtable甚至不允许单个null键和null值,那么如果键或值为null,则会引发NullPointerException。实例
«同步,线程安全
哈希表是内部同步的。因此,在多线程应用程序中使用Hashtable非常安全。其中as HashMap未在内部同步。因此,在没有外部同步的多线程应用程序中使用HashMap是不安全的。可以使用Collections.synchronizedMap()方法从外部同步HashMap。
«性能
由于Hashtable是内部同步的,这使得Hashtable比HashMap稍慢。
@See
红黑树是一种自平衡的二叉搜索树Java8中HashMap的性能改进
我的小贡献:
Hashtable和HashMap之间的第一个也是最重要的区别是,HashMap不是线程安全的,而Hashtable是线程安全的集合。Hashtable和HashMap之间的第二个重要区别是性能,因为HashMap不同步,所以性能比Hashtable好。Hashtable与HashMap的第三个区别是Hashtable是过时的类,应该在Java中使用ConcurrentHashMap代替Hashtable。