HashMap和Hashtable的区别总结
文章目錄
- 前言
- 源碼分析
- 繼承關系的不同:
- HashMap
- Hashtable
- 是否支持鍵值為null不同:
- HashMap
- Hashtable
- 初始化和擴容的方式不同:
- Hashtable
- HashMap
- 計算 hash 值的方法不同:
- HashTable
- HashMap
- 線程安全:
- 總結
前言
提示:HashMap和Hashtable是我們常用的兩個Map集合,我們都知道Hashtable可以保證線程安全,但其實他們的源碼實現上野有很多不同的,下面我們就針對源碼對HashMap和Hashtable重寫做一些研究。
提示:以下是本篇文章正文內容,下面案例可供參考
源碼分析
繼承關系的不同:
HashMap
HashMap 繼承 AbstractMap
public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, SerializableHashtable
HashTable 繼承 Dictionary
public class Hashtable<K,V>extends Dictionary<K,V>implements Map<K,V>, Cloneable, java.io.Serializable是否支持鍵值為null不同:
HashMap
HashMap 允許 null 值(key 和 value 都可以)。這樣的鍵只能有一個,可以有一個或者多個鍵所對應的值為 null 。
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 1sttreeifyBin(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 keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;}Hashtable
Hatable 不允許 null值(key 和 value 都不可以) key為 null 沒有 hash() ,value 為 null 的時候報異常
public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) { //value為null拋出NullPointerExceptionthrow 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;}private void addEntry(int hash, K key, V value, int index) {Entry<?,?> tab[] = table;if (count >= threshold) {// Rehash the table if the threshold is exceededrehash();tab = table;hash = key.hashCode();index = (hash & 0x7FFFFFFF) % tab.length;}// Creates the new entry.@SuppressWarnings("unchecked")Entry<K,V> e = (Entry<K,V>) tab[index];tab[index] = new Entry<>(hash, key, value, e);count++;modCount++;}初始化和擴容的方式不同:
Hashtable
public Hashtable() {this(11, 0.75f);//初始容量為11 } public Hashtable(int initialCapacity, float loadFactor) {if (initialCapacity < 0)throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal Load: "+loadFactor);if (initialCapacity==0)initialCapacity = 1;this.loadFactor = loadFactor;table = new Entry<?,?>[initialCapacity]; // new 初始化數組threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); }HashMap
HshMap的初始化在上偏文章中做了詳細介紹這里就好Hashtable()做比較就可以了
HashTable 在構造方法里面進行初始化,初始化大小為 11 每次擴容的時候變為原來的 2n+1 倍
HashMap調用默認構造是沒有初始化的 在第一次 調用 put 方法的時候,在 resize() 里面進行初始化,初始化大小為 16, 每次擴容后,變為原來的 2倍
計算 hash 值的方法不同:
HashTable
public synchronized V put(K key, V value) {// Make sure the value is not nullif (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
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); // 計算得到 } final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {// 這個方法前面有 }HashTable:直接調用 Object 的 hash() 函數,計算出來 hash 值,下標直接 數組長度取余得到
? int hash = key.hashCode();
? int index = (hash & 0x7FFFFFFF) % tab.length
Hash Map:首先 高位和低位異或得到 hash 值,然后 再和數組大小-1 做 與運算 得到下標
? int hash = key.hashCode() ^ (h >>> 16);
int index = (n - 1) & hash;
線程安全:
public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) {throw new NullPointerException();}HashTable的好多方法使用synchronized進行加鎖操作保證了線程安全
HashMap 線程不安全
總結
1、繼承的父類不一樣
HashTable :繼承 Dictionary HashMap:繼承AbstractMap2、線程安全
HashTable:線程安全 HashMap:線程不安全3、初始化的擴容不一樣
HashTable:在構造方法里面初始化,初始化大小為 11,每次擴容 2n+1 倍 HashMap:在 put 值的時候進行初始化,初始化大小為 16,每次擴容 2倍4、計算下標的方法不同
HashTable:hash值 直接調用 Object 類的HashCode() 方法,計算下標直接對數組長度取余 HashMap:hash值 是通過 高位和低位異或 得到,下標通過 數組長度 和 hash值進行與運算得到5、鍵和值 的 null 取值不同
HashTable:鍵和值都不允許為 null HashMap:鍵和值都可以為 null,只能有唯一的鍵值為 null,可以有多個值為 null總結
以上是生活随笔為你收集整理的HashMap和Hashtable的区别总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: List接口的三大实现类比较
- 下一篇: LinKedHashMap和TreeMa