HashMap和Hashtable區別的底層原理

程序員小迷 2024-05-12 11:53:32

一、容器鍵值對:

1.HashMap 的 key 和 value 都允許爲 null , HashMap 在 key 爲 null 的時候,值必須爲null。

2.Hashtable 的 key 和 value 都不允許爲 null 。 Hashtable 遇到key或value爲 null時 ,將抛出 NullPointerException異常 。

二、容量設定與擴容機制:

1.HashMap 默認初始化容量爲 16,並且容器容量一定是 2 的 n 次方。當元素數量達到容量和加載因子(加載因子LoadFactor,默認爲0.75)的乘積時會觸發擴容,並且是以原容量 2 倍 的方式 進行擴容。

2.Hashtable 默認初始化容量爲 11。

在元素數量達到容量和加載因子(加載因子默認是0.75)的乘積時會進行擴容,是以原容量 2 倍 再加 1 的方式進行擴容。即 int newCapacity = (oldCapacity << 1) + 1; 。

三、存儲位置:

1.HashMap 是先將 key 鍵的 hashCode 經過擾動函數擾動後得到 hash 值,然後再利用  hash & (length - 1) 的方式(由于 HashMap 的容器容量一定是 2 的 n 次方,所以可以使用 hash & (length- 1) 的方式代替取模的方式計算元素的位置從而提高運算效率)代替取模,得到元素的存儲位置。JDK 1.8之後HashMap引入了紅黑樹來優化鏈表過長的問題。

2.Hashtable 是使用除留余數法進行計算存儲位置的(因爲其默認容量不是2 的 n 次方,故無法用位運算替代模運算), int index = (hash &0x7FFFFFFF) % tab.length; 。

四、線程安全:

1.HashMap 不是線程安全,如果想線程安全,可以通過調用Collections.synchronizedMap(Map<K,V> m) 使其線程安全。或使用 ConcurrentHashMap 容器以同樣達到線程安全。

2.Hashtable 是線程安全的,每個操作方法都有 synchronized 修飾使其同步,但運行效率不高,所以建議使用 ConcurrentHashMap 容器以達到線程安全。

3.總結:

1)Hashtable 是一個古老的容器,如果我們不需要線程同步,則可以使用HashMap ,如果需要線程同步,則可以使用 ConcurrentHashMap 。

2)HashMap不是同步的,所以性能會比Hashtable要高。

五、遍曆及訪問

1.HashMap和Hashtable都支持使用Iterator進行遍曆。但是,Hashtable還額外支持使用Enumeration進行遍曆,但此方式已過時。

2.HashMap 的叠代器(Iterator)是 fail-fast 的。如在叠代過程中需要修改 HashMap的結構,除了通過叠代器的 remove() 方法是安全的之外,調用其他方法都會抛出 ConcurrentModificationException 異常。

Hashtable 的叠代器不是 fail-fast 的。

3.HashMap叠代順序不確定。Hashtable叠代順序按照插入順序進行。

4.Hashtable保留了containsKey、containsValue、contains三個方法,用于檢查是否包含某個鍵、值或鍵值對。

HashMap去掉了contains方法,只保留了containsKey和containsValue兩個方法。

六、其他

1.HashMap繼承自AbstractMap,實現了Map、Cloneable、Serializable接口。

2.Hashtable繼承自Dictionary,實現了Map、Cloneable、Serializable接口。

微風不燥,陽光正好,你就像風一樣經過這裏,願你停留的片刻溫暖舒心。

我是程序員小迷(致力于C、C++、Java、Kotlin、Android、Shell、JavaScript、TypeScript、Python等編程技術的技巧經驗分享),若作品對您有幫助,請關注、分享、點贊、收藏、在看、喜歡,您的支持是我們爲您提供幫助的最大動力。

歡迎關注。助您在編程路上越走越好!

0 阅读:0

程序員小迷

簡介:致力于Android、C等編程技術的技巧經驗分享