HashMap And HashTable

HashMap And HashTable

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同步?

HashMap能夠經過下面的語句進行同步:

Map m = Collections.synchronizeMap(hashMap);複製代碼

關於ConcurrentHashMap

public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
    implements ConcurrentMap<K,V>, Serializable {複製代碼

Hashtable和HashMap有幾個主要的不一樣:線程安全以及速度。僅在你須要徹底的線程安全的時候使用Hashtable,而若是你使用Java 5或以上的話,請使用ConcurrentHashMap吧。

若是有興趣和咱們一塊兒討論問題的話,不妨加下咱們羣吧 ,記得加羣的時候寫上我名字 ID:BigMoreKT:984370849

想要深刻學習的同窗們能夠加入QQ羣討論,有全套資源分享,經驗探討,沒錯,咱們等着你,分享互相的故事!

相關文章
相關標籤/搜索