先上HashTable的繼承關(guān)系:
為了方便比較同時(shí)放出HashMap的繼承關(guān)系:
可以看出HahMap和HashTable都實(shí)現(xiàn)了Map接口,只是父類(lèi)不一樣
HashTable的計(jì)算哈希是直接取得key本身的哈希:
int hash = key.hashCode();
這里可以看出纹冤,hashtable是不支持null值的芬迄,并且在put的時(shí)候取哈希之前已經(jīng)判定了value為空判定于样,雖然key沒(méi)有判定,但是在取hash的時(shí)候由于key是null所以一定會(huì)拋出java.lang.NullPointerException
if (value == null) {
throw new NullPointerException();
}
HashTable每次擴(kuò)容是原有容量的2倍+1( (oldCapacity << 1) + 1),通過(guò)rehash()來(lái)實(shí)現(xiàn)擴(kuò)容的
HashTable是的每個(gè)哈希桶的元素都是鏈表,相對(duì)來(lái)說(shuō)如果每個(gè)哈希桶元素比較多的話萨西,處理效率是比較低的如输,接下來(lái)劃重點(diǎn)鼓黔,這實(shí)質(zhì)就是哈希表的實(shí)質(zhì),一張課表
我們首先取得今天的日期不见,比如星期三澳化,然后一節(jié)一節(jié)比較,尋找文體活動(dòng)這門(mén)課稳吮,畢竟大家都不喜歡上課缎谷,過(guò)程和HashTable完全一致
哈希桶就相當(dāng)于一個(gè)表格,首先從X軸取得哈希桶位置再在Y軸比較獲取元素真實(shí)位置灶似。
HashTable的計(jì)算索引的方式是:
(hash & 0x7FFFFFFF) % tab.length
這里為什么要與0x7FFFFFFF是因?yàn)镠ash的值會(huì)是負(fù)數(shù)列林,0x7FFFFFFF是Integer.MAX_VALUE,使用Math.abs()也可以達(dá)到想用的效果,但是為什么不用它呢
主要原因如下圖所示:
可以看到當(dāng)hash為Integer的最小值的時(shí)候酪惭,會(huì)導(dǎo)致Math.abs取得負(fù)數(shù)值希痴,這樣計(jì)算出來(lái)的index下標(biāo)也是負(fù)值,而java的數(shù)組下標(biāo)不能為負(fù)數(shù)春感,否則會(huì)導(dǎo)致程序異常
最終將node追加到哈希哈希桶某個(gè)哈西位置的尾部砌创,就完成了整個(gè)存儲(chǔ)過(guò)程
需要注意的是:HashTable是線程安全的,HashTable所有public方法都添加了synchronized關(guān)鍵字鲫懒,保證線程同步不會(huì)出錯(cuò)嫩实。但是同時(shí)因?yàn)榫€程安全機(jī)制導(dǎo)致HashTable的存取效率不如HashMap
比較上一篇文章 JDK HashMap詳解 而言,HashTable雖然都實(shí)現(xiàn)了Map接口窥岩,但各自有著不同的應(yīng)用場(chǎng)景甲献,總結(jié)起來(lái)有如下不同點(diǎn):
- HashTable是線程安全的,HashMap是線程不安全的
- HashTable允許K,V均可以為null谦秧,但是HashMap不能為null竟纳,否則會(huì)有空指針異常
- 計(jì)算Hash的方式不同,HashTable計(jì)算哈希的方式是直接取key本身的hash疚鲤,而HashMap計(jì)算hash的方式為:(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16) 自身哈希和哈希無(wú)符號(hào)右移16位做與運(yùn)算锥累,之所以會(huì)有這種差異是因?yàn)镠ashTable和HashTable計(jì)算索引方式不同,HashTable直接與當(dāng)前長(zhǎng)度取余獲取當(dāng)前索引集歇,而HashMap通過(guò)公式((size - 1) & hash)計(jì)算索引值
- 數(shù)據(jù)結(jié)構(gòu)不同:HashTable采用的是鏈表形式桶略,而HashMap采用的是閾值以下用鏈表閾值以上用紅黑樹(shù)的數(shù)據(jù)結(jié)構(gòu)
- 存取效率:HashTable的效率相對(duì)比較低,因?yàn)橛衧ynchronized關(guān)鍵字做線程同步,HashMap存取效率比較高际歼,因?yàn)闆](méi)有鎖的限制惶翻,但因?yàn)槠洳皇蔷€程安全的,在線程安全場(chǎng)景下需要進(jìn)行一些線程同步操作
- 在查詢包含關(guān)系的時(shí)候鹅心,HashTable提供的是contains(),containsKey()和containsValue()方法吕粗,而hashMap把只有兩個(gè)分別為:containsKey()和containsValue()
- HashTable是官方建議被替換的以下來(lái)自于JDK8中的注釋
If a thread-safe implementation is not needed, it is recommended to use
{@link HashMap} in place of {@code Hashtable}. If a thread-safe
highly-concurrent implementation is desired, then it is recommended
to use {@link java.util.concurrent.ConcurrentHashMap} in place of
{@code Hashtable}.
大致含義為:如果你不需要線程同步,建議使用HashMap來(lái)代替HashTable旭愧,如果你的你是需要線程同步的話使用ConcurrentHashMap來(lái)替代Hashtable