Answers:
Hashtable
是同步的,而HashMap
不是。这HashMap
对于非线程应用程序更好,因为非同步对象通常比同步对象执行得更好。
Hashtable
不允许null
键或值。 HashMap
允许一个null
键和任意数量的null
值。
HashMap的子类之一是LinkedHashMap
,因此,如果您想要可预测的迭代顺序(默认情况下为插入顺序),则可以轻松地将替换HashMap
为LinkedHashMap
。如果您使用,这将不那么容易Hashtable
。
由于同步对您来说不是问题,因此建议您HashMap
。如果同步成为问题,您也可以查看ConcurrentHashMap
。
Collections.synchronizedMap()
。
Hashtable
方法(“同步每种方法都应解决任何并发问题!”)使线程应用程序变得更加糟糕。您最好从外部进行同步HashMap
(并考虑后果),或使用ConcurrentMap
实现(并利用其扩展的API进行并发)。底线:唯一的原因Hashtable
是当旧版API(从1996年开始)需要它时。
请注意,很多答案都说明Hashtable已同步。 在实践中,这几乎买不到您。 同步在访问器/更改器方法上将停止同时从映射中添加或删除两个线程,但是在现实世界中,您经常需要进行额外的同步。
一个非常常见的习惯用法是“先检查后放入”,即在中查找一个条目,Map
如果尚不存在,则将其添加。无论您使用Hashtable
还是,这都不是原子操作HashMap
。
等效同步HashMap
可以通过以下方式获得:
Collections.synchronizedMap(myMap);
但是要正确实现此逻辑,您需要对表单进行额外的同步:
synchronized(myMap) {
if (!myMap.containsKey("tomato"))
myMap.put("tomato", "red");
}
除非您还防止通过额外的同步来修改Hashtable
的条目,否则即使迭代一个的条目(或由HashMap
获取的Collections.synchronizedMap
)也不是线程安全的Map
。
ConcurrentMap
接口的实现(例如ConcurrentHashMap
)通过包括线程安全的“先检查后行为”语义来解决其中的一些问题,例如:
ConcurrentMap.putIfAbsent(key, value);
Hashtable
被认为是遗留代码。没有任何事情Hashtable
是无法使用HashMap
或推导完成的HashMap
,因此对于新代码,我看不出回到的任何理由Hashtable
。
面试中经常会问这个问题,以检查应聘者是否理解收集类的正确用法,并了解可用的替代解决方案。
HashMap
类是大致相当于Hashtable
,除了它是非同步并且允许空值。(HashMap
允许将空值用作键和值,而Hashtable
不允许使用null
s)。HashMap
不保证地图的顺序会随着时间的推移保持不变。HashMap
是不同步而已Hashtable
同步。HashMap
是安全的,而如果没有其他线程通过添加或删除除自身 方法之外的任何元素来结构性地修改映射,则为的枚举器为false Hashtable
并抛出。但这不是保证的行为,将由JVM尽力而为。ConcurrentModificationException
Iterator
remove()
关于一些重要术语的注意事项:
Hashtable
都必须获取对象的锁,而其他将等待释放锁。set
不会“结构化”地修改集合,但可能会调用方法。但是,如果在调用之前对set
集合进行了结构上的修改,IllegalArgumentException
则将引发该集合。HashMap
可以通过同步
Map m = Collections.synchronizeMap(hashMap);
Map提供了Collection视图,而不是通过Enumeration对象直接支持迭代。集合视图极大地增强了接口的表达能力,如本节后面所述。Map允许您迭代键,值或键值对;
Hashtable
不提供第三个选项。Map提供了一种在迭代过程中删除条目的安全方法;Hashtable
没有。最后,Map修复了Hashtable
界面中的一个小缺陷。
Hashtable
有一个名为contains的方法,如果Hashtable
contains包含给定值,则返回true
。给定其名称,如果Hashtable
包含一个给定的键,则您希望该方法返回true ,因为该键是的主要访问机制Hashtable
。Map界面通过重命名方法消除了这种混乱的根源
containsValue
。同样,这也提高了接口的一致性
containsValue
-parallels containsKey
。
set
操作HashMap
。3)如果有以前的更改,该put(...)
操作将不会抛出IllegalArgumentException
。4)如果您更改映射,HashMap
也会发生快速故障行为。5)快速失败行为的保证。(HashTable
如果您进行并发修改,则不能保证a的行为。实际行为是...不可预测的。)
Hashtable
也不保证地图元素的顺序也会随着时间的推移而保持稳定。(你也许混淆Hashtable
与LinkedHashMap
)
thing.set(thing.get() + 1);
它经常完全不受保护,而使新手大吃一惊,特别是如果get()
and set()
方法是同步方法。他们中的许多人都在期待魔术。
请记住,这HashTable
是引入Java Collections Framework(JCF)之前的遗留类,后来又进行了改进以实现该Map
接口。所以是Vector
和Stack
。
因此,由于其他人指出的,JCF中总是有更好的替代方法,因此请始终远离新代码。
这是Java收集备忘单,您会发现它很有用。请注意,灰色块包含旧类HashTable,Vector和Stack。
已经发布了许多好的答案。我要添加一些新观点并进行总结。
HashMap
和Hashtable
两者都用于存储在键和值形式的数据。两者都使用哈希技术来存储唯一密钥。但是,下面给出的HashMap和Hashtable类之间有许多区别。
哈希图
HashMap
不同步。它不是线程安全的,没有适当的同步代码就无法在许多线程之间共享。 HashMap
允许一个空键和多个空值。 HashMap
是JDK 1.2中引入的新类。 HashMap
很快 HashMap
通过调用此代码使as同步Map m = Collections.synchronizedMap(HashMap);
HashMap
被Iterator遍历。 HashMap
是快速失败的。 HashMap
继承AbstractMap类。 哈希表
Hashtable
已同步。它是线程安全的,可以与许多线程共享。 Hashtable
不允许使用任何null键或值。 Hashtable
是一个遗留类。 Hashtable
是慢的。 Hashtable
是内部同步的,不能不同步。 Hashtable
被Enumerator和Iterator遍历。 Hashtable
器不是快速失败的。 Hashtable
继承Dictionary类。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中,我们还被承诺能够像使用良好的旧脚本语言一样构造和访问HashMaps:
Map<String,Integer> map = { "orange" : 12, "apples" : 15 };
map["apples"];
更新:不,他们不会登陆1.8 ... :(
HashTable是同步的,如果您在单个线程中使用它,则可以使用HashMap,它是未同步的版本。不同步的对象通常具有更高的性能。顺便说一下,如果多个线程同时访问HashMap,并且其中至少一个线程在结构上修改了映射,则必须在外部进行同步。Youn可以使用以下命令将未同步的地图包装到同步地图中:
Map m = Collections.synchronizedMap(new HashMap(...));
HashTable只能包含非null对象作为键或值。HashMap可以包含一个null键和null值。
Map返回的迭代器是快速失败的,如果在创建迭代器后的任何时候都对结构进行了结构修改,则除了通过迭代器自己的remove方法之外,该迭代器都将抛出ConcurrentModificationException
。因此,面对并发修改,迭代器将迅速而干净地失败,而不是冒着在未来不确定的时间冒任意,不确定的行为的风险。而 Hashtable的keys和elements方法返回的枚举并不是快速失败的。
HashTable和HashMap是Java Collections Framework的成员(自Java 2平台v1.2起,对HashTable进行了改进以实现Map接口)。
HashTable被认为是遗留代码,如果需要线程安全的高并发实现,文档建议使用ConcurrentHashMap代替Hashtable。
HashMap不保证返回元素的顺序。对于HashTable,我想是相同的,但我不确定,我没有找到明确指出这一点的资源。
HashMap
并且Hashtable
在算法上也有很大差异。以前没有人提到过这,所以这就是为什么我提起它。HashMap
会构造一个具有两个大小幂的哈希表,并动态地增加哈希表,以使您在任何存储桶中最多具有八个元素(冲突),并且对于常规元素类型而言,这些元素将得到很好的搅动。但是,那Hashtable
如果您知道自己在做什么实现可以更好地控制散列,即可以使用例如最接近值域大小的素数来固定表大小,这将导致比HashMap更好的性能,即减少冲突在某些情况下。
除了在这个问题中广泛讨论的明显差异之外,我将Hashtable视为“手动驱动”汽车,在其中您可以更好地控制哈希,而将HashMap视为通常可以很好执行的“自动驱动”副本。
根据这里的信息,我建议您使用HashMap。我认为最大的好处是Java会阻止您在对其进行迭代时对其进行修改,除非您通过迭代器进行修改。
A- Collection
有时称为容器-只是将多个元素分组为一个单元的对象。Collection
s用于存储,检索,操作和传达聚合数据。集合框架W是用于表示和操作集合的统一体系结构。
的HashMap
JDK1.2
和Hashtable JDK1.0
,两者都用来表示一组在表示的对象的<Key, Value>
一对。每<Key, Value>
对称为Entry
对象。参赛作品的收集是由对象简称HashMap
和Hashtable
。集合中的键必须唯一或独特。[因为它们用于检索特定键的映射值。集合中的值可以重复。]
« 超类,旧版和收集框架成员
Hashtable是引入的旧类JDK1.0
,它是Dictionary类的子类。对JDK1.2
Hashtable进行了重新设计,以实现Map接口以使其成为集合框架的成员。HashMap从Java引入框架开始就是Java Collection Framework的成员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)构造一个空哈希表。其中,as Hashtable构造具有默认初始容量(11)和负载因子/填充比(0.75)的空哈希表。
« 发生哈希冲突时进行结构修改
HashMap
,Hashtable
如果发生哈希冲突,则会将地图条目存储在链接列表中。从Java8开始,HashMap
如果哈希存储桶超过某个阈值,该存储桶将从切换linked list of entries to a balanced tree
。可以将最坏情况下的性能从O(n)提高到O(log n)。在将列表转换为二叉树时,哈希码用作分支变量。如果在同一存储桶中有两个不同的哈希码,则认为一个更大,并在树的右边,另一个在左边。但是,当两个哈希码相等时,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 |
+--------------------+-----------+-------------+
Iterator
本质上是快速失败的。也就是说,如果在迭代而不是其自身的remove()方法的同时修改了集合,则抛出ConcurrentModificationException。Enumeration
本质上,故障保护在哪里。如果在迭代过程中修改了集合,它不会引发任何异常。
根据Java API文档,迭代器始终优先于枚举。
注意:迭代器接口重复了Enumeration接口的功能。此外,Iterator添加了可选的remove操作,并且具有较短的方法名称。新的实现应考虑优先使用Iterator而不是Enumeration。
在Java 5中引入了ConcurrentMap接口:ConcurrentHashMap
- ConcurrentMap
由哈希表支持的高度并发,高性能实现。此实现在执行检索时不会阻塞,并允许客户端选择用于更新的并发级别。它旨在替代Hashtable
:除了实现之外ConcurrentMap
,它还支持所有特有的“传统”方法Hashtable
。
每个HashMapEntry
s值都是易挥发的,从而确保了精细的一致性,以应对竞争性修改和后续读取;每次读取均反映最近完成的更新
迭代器和枚举是故障安全的-反映自创建迭代器/枚举以来的某个时刻的状态;这允许同时读取和修改,但以降低一致性为代价。他们不抛出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
内部同步。因此,Hashtable
在多线程应用程序中使用非常安全。其中as HashMap
内部未同步。因此,HashMap
在没有外部同步的情况下在多线程应用程序中使用是不安全的。您可以HashMap
使用Collections.synchronizedMap()
方法从外部进行同步。
« 表现
由于Hashtable
是内部同步的,因此Hashtable
比慢HashMap
。
@看到
1. Hashmap
和HashTable
两个存储键和值。
2. Hashmap
可以将一个密钥存储为null
。Hashtable
不能储存null
。
3. HashMap
不同步但Hashtable
已同步。
4. HashMap
可以与Collection.SyncronizedMap(map)
Map hashmap = new HashMap();
Map map = Collections.SyncronizedMap(hashmap);
除了已经提到的差异,应该指出的是,自从Java 8,HashMap
动态替换每个桶使用树节点(红黑树)的节点(链表),这样,即使高哈希冲突存在,最坏的情况下,当搜索是
O(log(n))与HashMap
Vs O(n)的关系Hashtable
。
*上述改进还没有被应用到Hashtable
还没有,但只HashMap
,LinkedHashMap
和ConcurrentHashMap
。
仅供参考,目前,
TREEIFY_THRESHOLD = 8
:如果存储桶包含8个以上的节点,则链表将转换为平衡树。UNTREEIFY_THRESHOLD = 6
:当存储桶太小(由于删除或调整大小)时,树将转换回链表。HashTable和HashMaps有5个基本区别。
我的小贡献:
首先,也是最显著之间的不同
Hashtable
和HashMap
是,HashMap
是不是线程安全的,同时Hashtable
是一个线程安全的集合。
Hashtable
和之间的第二个重要区别HashMap
是性能,由于HashMap
未同步,因此其性能优于Hashtable
。关于第三个区别
Hashtable
VSHashMap
是Hashtable
已经过时的类,你应该使用ConcurrentHashMap
代替Hashtable
Java编写的。
HashMap:这是java.util包中可用的类,用于以键和值格式存储元素。
Hashtable:它是一个遗留类,正在收集框架中被识别。
Hashtable
是同步的,而HashMap
不是同步的。HashMap
是故障安全的,而中的迭代器Hashtable
不是。如果您在迭代时更改地图,就会知道。HashMap
允许其中包含null值,而Hashtable
不允许。HashMap和HashTable
1)Hashtable和Hashmap实现java.util.Map接口2)Hashmap和Hashtable都是基于哈希的集合。和致力于哈希。所以这些是HashMap和HashTable的相似之处。
1)第一个区别是HashMap不是线程安全的,而HashTable是ThreadSafe
2)HashMap在性能上更好,因为它不是线程安全的。Hashtable性能明智的方法并不是更好,因为它是线程安全的。因此,多个线程无法同时访问Hashtable。
Hashtable:
哈希表是保留键值对值的数据结构。键和值都不允许为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:
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));
}
}
HashMap
是模拟的,因此可以使用,GWT client code
而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 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。