HashMap和HashTable的區(qū)別

Java常見(jiàn)比較一

1.線程是否安全?

HashMap 是非線程安全的,HashTable 是線程安全的;HashTable 內(nèi)部的方法基本都經(jīng)過(guò)synchronized修飾。(如果你要保證線程安全,可以使用ConcurrentHashmap)

2.效率

因?yàn)榫€程安全的問(wèn)題,Hashmap 要比 HashTable 效率高一點(diǎn)。不建議使用 HashTable。

3.對(duì) Null key 和 Null value 的支持

HashMap 中,null 可以作為鍵,這樣的鍵只有一個(gè),可以有一個(gè)或者多個(gè)鍵所對(duì)應(yīng)額的值為 null。但是在 HashTable 中鍵值為null,將報(bào)NullPointerException。

4.初始容量大小和每次擴(kuò)充容量大小的不同

① 創(chuàng)建時(shí)如果不指定容量初始值,Hashtable 默認(rèn)值的初始大小為11,之后每次擴(kuò)充,容量變?yōu)樵瓉?lái)的 2n+1。HashMap 默認(rèn)的初始值為16,之后每次擴(kuò)充,容量變?yōu)樵瓉?lái)的 2 倍。
②創(chuàng)建時(shí)如果給定了容量初始值,那么 Hashtable 會(huì)直接使用你給定的大小,而HashMap 會(huì)將其擴(kuò)充為 2 的冪次方大小。也就是說(shuō) HashMap 總是使用 2 的冪作為哈希表的大小。

5.底層數(shù)據(jù)結(jié)構(gòu)

JDK1.8 以后的 HashMap 在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長(zhǎng)度大于閾值(默認(rèn)為8)時(shí),將鏈表轉(zhuǎn)化為紅黑樹(shù),以減少搜索時(shí)間。Hashtable 沒(méi)有這樣的機(jī)制。

HashMap 中帶有初始容量的構(gòu)造函數(shù):

public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
 }
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
 }

下面這個(gè)方法保證了 HashMap總是使用 2 的冪作為哈希表的大?。?/p>

 /**
  * Returns a power of two size for the given target capacity.
  */
  static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
 }

HashMap的長(zhǎng)度為什么是 2 的冪次方?

為了能讓 HashMap存取搞笑,盡量較少碰撞,也就是要盡量把數(shù)據(jù)分配均勻。Hash 值的范圍值 -2147483648 到 2147483647,前面加起來(lái)大概 40 億長(zhǎng)度的數(shù)組,內(nèi)存是放不下的。所以這個(gè)散列值是不能直接拿來(lái)用的。要先對(duì)數(shù)組的長(zhǎng)度取模運(yùn)算,得到的余數(shù)才能用要存放的位置也就是對(duì)應(yīng)的數(shù)組下標(biāo)。這個(gè)數(shù)組下標(biāo)的計(jì)算方法是“(n-1)& hash”。(n代表數(shù)組長(zhǎng)度)這也就解釋了 HashMap 的長(zhǎng)度為什么是 2 的冪次方。

這個(gè)算法應(yīng)該如何設(shè)計(jì)

我們首先可能會(huì)想到采用%取余的操作來(lái)實(shí)現(xiàn)。但是,重點(diǎn)來(lái)了:“取余(%)操作中如果除數(shù)是 2 的冪次則等價(jià)于與其除數(shù)減一的與(&)操作(也就是說(shuō) hash%length==hash&(length-1)的前提是 length 是 2 的 n 次方)” 并且采用二進(jìn)制位操作 &,相對(duì)于 % 能夠提高運(yùn)算效率,這就解釋了 HashMap 的長(zhǎng)度為什么是 2 的冪次方。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容