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羣討論,有全套資源分享,經驗探討,沒錯,咱們等着你,分享互相的故事!