HashMap和Hashtable两个类都实现了Map接口,两者保存K-V对(key-value对);HashSet则实现了Set接口,性质相似于集合。Hashtable的应用很是普遍,HashMap是新框架中用来代替Hashtable的类,也就是说建议使用HashMap,不要使用Hashtable。可能你以为Hashtable很好用,为何不用呢?这里简单分析他们的区别。java
1、继承的父类不一样api
Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类,HashMap是Java1.2引进的Mapinterface 的一个实现。但两者都实现了Map接口。数组
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {复制代码
2、线程安全性不一样安全
Hashtable 中的方法是Synchronize的,而HashMap中的方法在缺省状况下是非Synchronize的。在多线程并发的环境下,能够直接使用Hashtable,不须要本身为它的方法实现同步,但使用HashMap时就必需要本身增长同步处理。多线程
HashTable并发
public synchronized boolean isEmpty() {
return count == 0;
}复制代码
HashMapapp
public boolean isEmpty() {
return size == 0;
}复制代码
3、是否提供contains方法框架
HashMap把Hashtable的contains方法去掉了,改为containsValue和containsKey,由于contains方法容易让人引发误解。Hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同,实际上containsValue调用的是contains方法。学习
public synchronized boolean contains(Object value) {
if (value == null) {
throw new NullPointerException();
}
Entry<?,?> tab[] = table;
for (int i = tab.length ; i-- > 0 ;) {
for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
if (e.value.equals(value)) {
return true;
}
}
}
return false;
}
public boolean containsValue(Object value) {
return contains(value);
}复制代码
4、key和value是否容许null值this
其中key和value都是对象,而且不能包含重复key,但能够包含重复的value。Hashtable中,key和value都不容许出现null值。HashMap中,null能够做为键,这样的键只有一个;能够有一个或多个键所对应的值为null。当get()方法返回null值时,多是 HashMap中没有该键,也可能使该键所对应的值为null。所以,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
HashTable
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
addEntry(hash, key, value, index);
return null;
}复制代码
HashMap
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}复制代码
5、两个遍历方式的内部实现上不一样
Hashtable、HashMap都使用了 Iterator。而因为历史缘由,Hashtable还使用了Enumeration的方式 。
6、hash值不一样
哈希值的使用不一样,HashTable直接使用对象的hashCode。而HashMap从新计算hash值。
7、内部实现使用的数组初始化和扩容方式不一样
Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增长的方式是 old*2+1。HashMap中hash数组的默认大小是16,并且必定是2的指数。
Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
HashMap能够经过下面的语句进行同步:
Map m = Collections.synchronizeMap(hashMap);复制代码
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable {复制代码
Hashtable和HashMap有几个主要的不一样:线程安全以及速度。仅在你须要彻底的线程安全的时候使用Hashtable,而若是你使用Java 5或以上的话,请使用ConcurrentHashMap吧。
想要深刻学习的同窗们能够加入QQ群讨论,有全套资源分享,经验探讨,没错,咱们等着你,分享互相的故事!