java複習之HashMap和Hashtable的區別

Inequality-Sign發表於2018-03-20

1.兩者繼承結構不同
雖然都實現了Map、Cloneable、Serializable三個介面。但是HashMap繼承自抽象類AbstractMap,而HashTable繼承自抽象類Dictionary。其中Dictionary類是一個已經被廢棄的類,這一點我們可以從它程式碼的註釋中看到:

以下程式碼及註釋來自java.util.Dictionary

* <strong>NOTE: This class is obsolete. New implementations should
* implement the Map interface, rather than extending this class.</strong>
*

2.HashMap支援空的鍵值 而HashTable在遇到null時,會丟擲NullPointerException異常
這並不是因為HashTable有什麼特殊的實現層面的原因導致不能支援null鍵和null值,這僅僅是因為HashMap在實現時對null做了特殊處理,將null的hashCode值定為了0,從而將其存放在雜湊表的第0個bucket中。我們一put方法為例,看一看程式碼的細節:

以下程式碼及註釋來自java.util.HashTable

public synchronized V put(K key, V value) {

    // 如果value為null,丟擲NullPointerException
    if (value == null) {
        throw new NullPointerException();
    }

    // 如果key為null,在呼叫key.hashCode()時丟擲NullPointerException

    // ...
}


以下程式碼及註釋來自java.util.HasMap

public V put(K key, V value) {
    if (table == EMPTY_TABLE) {
        inflateTable(threshold);
    }
    // 當key為null時,呼叫putForNullKey特殊處理
    if (key == null)
        return putForNullKey(value);
    // ...
}

private V putForNullKey(V value) {
    // key為null時,放到table[0]也就是第0個bucket中
    for (Entry<K,V> e = table[0]; e != null; e = e.next) {
        if (e.key == null) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }
    modCount++;
    addEntry(0, null, value, 0);
    return null;
}

3.執行緒安全
我們說HashTable是同步的,HashMap不是,也就是說HashTable在多執行緒使用的情況下,不需要做額外的同步,而HashMap則不行。那麼HashTable是怎麼做到的呢?

以下程式碼及註釋來自java.util.HashTable

public synchronized V get(Object key) {
    Entry tab[] = table;
    int hash = hash(key);
    int index = (hash & 0x7FFFFFFF) % tab.length;
    for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
        if ((e.hash == hash) && e.key.equals(key)) {
            return e.value;
        }
    }
    return null;
}

public Set<K> keySet() {
    if (keySet == null)
        keySet = Collections.synchronizedSet(new KeySet(), this);
    return keySet;
}

可以看到,也比較簡單,就是公開的方法比如get都使用了synchronized描述符。而遍歷檢視比如keySet都使用了Collections.synchronizedXXX進行了同步包裝。

相關文章