前言:
又是一個大好的周末, 可惜今天起來有點晚, 扒開HashMap和HashTable, 看看他們到底有什么區別吧.
先來一段比較拗口的定義:
Hashtable 的實例有兩個參數影響其性能:初始容量 和 加載因子。容量 是哈希表中桶 的數量,初始容量 就是哈希表創建時的容量。注意,哈希表的狀態為 open:在發生“哈希沖突”的情況下,單個桶會存儲多個條目,這些條目必須按順序搜索。加載因子 是對哈希表在其容量自動增加之前可以達到多滿的一個尺度。初始容量和加載因子這兩個參數只是對該實現的提示。關於何時以及是否調用 rehash 方法的具體細節則依賴於該實現。
而HashTable是 基於哈希表的 Map 接口的實現。此實現提供所有可選的映射操作,並允許使用 null 值和 null 鍵。(除了非同步和允許使用 null 之外,HashMap 類與 Hashtable 大致相同。)此類不保證映射的順序,特別是它不保證該順序恆久不變。 此實現假定哈希函數將元素適 當地分布在各桶之間,可為基本操作(get 和 put)提供穩定的性能。迭代 collection 視圖所需的時間與 HashMap 實例的“容量”(桶的數量)及其大小(鍵-值映射關系數)成比例。所以,如果迭代性能很重要,則不要將初始容量設置得太高(或將加載因子設置得太低)。
一, 實例舉證
1
2 public static void main(String[] args) { 3 Map<String, String> map = new HashMap<String, String>(); 4 map.put("a", "aaa"); 5 map.put("b", "bbb"); 6 map.put("c", "ccc"); 7 map.put("d", "ddd"); 8 Iterator<String> iterator = map.keySet().iterator(); 9 while (iterator.hasNext()) { 10 Object key = iterator.next(); 11 System.out.println("map.get(key) is :" + map.get(key)); 12 } 13
14 Hashtable<String, String> tab = new Hashtable<String, String>(); 15 tab.put("a", "aaa"); 16 tab.put("b", "bbb"); 17 tab.put("c", "ccc"); 18 tab.put("d", "ddd"); 19 Iterator<String> iterator_1 = tab.keySet().iterator(); 20 while (iterator_1.hasNext()) { 21 Object key = iterator_1.next(); 22 System.out.println("tab.get(key) is :" + tab.get(key)); 23 } 24 } 25 }
首先上面有這么一段代碼, 那么它的輸出是什么呢?
可以看到, HashMap按照正常順序輸出, 而HashTable輸出的順序卻有些詭異.
2, 源碼分析
看到上面的結果, 那么我們就分別來看下HashMap和HashTable的源碼吧.
首先我要來灌輸一些思想, 然后再根據這些定義的規則(前人總結出來的) 再去源碼中一探究竟.
1)HashTable是同步的,HashMap是非同步的
HashTable中put和get方法:
1 public synchronized V put(K key, V value) { 2 // Make sure the value is not null
3 if (value == null) { 4 throw new NullPointerException(); 5 } 6
7 // Makes sure the key is not already in the hashtable.
8 Entry<?,?> tab[] = table; 9 int hash = key.hashCode(); 10 int index = (hash & 0x7FFFFFFF) % tab.length; 11 @SuppressWarnings("unchecked") 12 Entry<K,V> entry = (Entry<K,V>)tab[index]; 13 for(; entry != null ; entry = entry.next) { 14 if ((entry.hash == hash) && entry.key.equals(key)) { 15 V old = entry.value; 16 entry.value = value; 17 return old; 18 } 19 } 20
21 addEntry(hash, key, value, index); 22 return null; 23 }
1 public synchronized V get(Object key) { 2 Entry<?,?> tab[] = table; 3 int hash = key.hashCode(); 4 int index = (hash & 0x7FFFFFFF) % tab.length; 5 for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { 6 if ((e.hash == hash) && e.key.equals(key)) { 7 return (V)e.value; 8 } 9 } 10 return null; 11 }
HashMap中put和get方法:
1 public V put(K key, V value) { 2 return putVal(hash(key), key, value, false, true); 3 }
1 public V get(Object key) { 2 Node<K,V> e; 3 return (e = getNode(hash(key), key)) == null ? null : e.value; 4 }
從以上代碼中就能顯而易見的看到HashTable中的put和get方法是被synchronized修飾的, 這種做的區別呢?
由於非線程安全,效率上可能高於Hashtable. 如果當多個線程訪問時, 我們可以使用HashTable或者通過Collections.synchronizedMap來同步HashMap。
2)HashTable與HashMap實現的接口一致,但HashTable繼承自Dictionary,而HashMap繼承自AbstractMap;
HashTable:
HashMap:
3)HashTable不允許null值(key和value都不可以) ,HashMap允許null值(key和value都可以)。
在1中我們可以看到HashTable如果value為null就會直接拋出: throw new NullPointerException();
那么再看看HashMap put value 具體做了什么?
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 1st treeifyBin(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 key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
由此可見, 並沒有value值進行強制的nullCheck.
4)HashTable有一個contains(Object value)功能和containsValue(Object value)功能一樣。
這里我們可以直接對比HashMap和HashTable有關Contains的方法:
HashTable中的contains方法在HashMap中就被取消了, 那么我們來具體看下HashTable中的contains方法的作用:
1 public synchronized boolean contains(Object value) { 2 if (value == null) { 3 throw new NullPointerException(); 4 } 5
6 Entry<?,?> tab[] = table; 7 for (int i = tab.length ; i-- > 0 ;) {
8 for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) { 9 if (e.value.equals(value)) { 10 return true; 11 } 12 } 13 } 14 return false; 15 }
然后再看下HashTable中的containsValue方法:
1 public boolean containsValue(Object value) { 2 return contains(value); 3 }
這里就很明顯了, contains方法其實做的事情就是containsValue, 里面將value值使用equals進行對比, 所以在HashTable中直接取消了contains方法而是使用containsValue代替.
5)HashTable使用Enumeration進行遍歷,HashMap使用Iterator進行遍歷。
首先是HashTable中:

1 private class Enumerator<T> implements Enumeration<T>, Iterator<T> { 2 Entry<?,?>[] table = Hashtable.this.table; 3 int index = table.length; 4 Entry<?,?> entry; 5 Entry<?,?> lastReturned; 6 int type; 7
8 /**
9 * Indicates whether this Enumerator is serving as an Iterator 10 * or an Enumeration. (true -> Iterator). 11 */
12 boolean iterator; 13
14 /**
15 * The modCount value that the iterator believes that the backing 16 * Hashtable should have. If this expectation is violated, the iterator 17 * has detected concurrent modification. 18 */
19 protected int expectedModCount = modCount; 20
21 Enumerator(int type, boolean iterator) { 22 this.type = type; 23 this.iterator = iterator; 24 } 25
26 public boolean hasMoreElements() { 27 Entry<?,?> e = entry; 28 int i = index; 29 Entry<?,?>[] t = table; 30 /* Use locals for faster loop iteration */
31 while (e == null && i > 0) { 32 e = t[--i]; 33 } 34 entry = e; 35 index = i; 36 return e != null; 37 } 38
39 @SuppressWarnings("unchecked") 40 public T nextElement() { 41 Entry<?,?> et = entry; 42 int i = index; 43 Entry<?,?>[] t = table; 44 /* Use locals for faster loop iteration */
45 while (et == null && i > 0) { 46 et = t[--i]; 47 } 48 entry = et; 49 index = i; 50 if (et != null) { 51 Entry<?,?> e = lastReturned = entry; 52 entry = e.next; 53 return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e); 54 } 55 throw new NoSuchElementException("Hashtable Enumerator"); 56 } 57
58 // Iterator methods
59 public boolean hasNext() { 60 return hasMoreElements(); 61 } 62
63 public T next() { 64 if (modCount != expectedModCount) 65 throw new ConcurrentModificationException(); 66 return nextElement(); 67 } 68
69 public void remove() { 70 if (!iterator) 71 throw new UnsupportedOperationException(); 72 if (lastReturned == null) 73 throw new IllegalStateException("Hashtable Enumerator"); 74 if (modCount != expectedModCount) 75 throw new ConcurrentModificationException(); 76
77 synchronized(Hashtable.this) { 78 Entry<?,?>[] tab = Hashtable.this.table; 79 int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; 80
81 @SuppressWarnings("unchecked") 82 Entry<K,V> e = (Entry<K,V>)tab[index]; 83 for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) { 84 if (e == lastReturned) { 85 modCount++; 86 expectedModCount++; 87 if (prev == null) 88 tab[index] = e.next; 89 else
90 prev.next = e.next; 91 count--; 92 lastReturned = null; 93 return; 94 } 95 } 96 throw new ConcurrentModificationException(); 97 } 98 } 99 }
然后是HashMap中:

1 abstract class HashIterator { 2 Node<K,V> next; // next entry to return
3 Node<K,V> current; // current entry
4 int expectedModCount; // for fast-fail
5 int index; // current slot
6
7 HashIterator() { 8 expectedModCount = modCount; 9 Node<K,V>[] t = table; 10 current = next = null; 11 index = 0; 12 if (t != null && size > 0) { // advance to first entry
13 do {} while (index < t.length && (next = t[index++]) == null); 14 } 15 } 16
17 public final boolean hasNext() { 18 return next != null; 19 } 20
21 final Node<K,V> nextNode() { 22 Node<K,V>[] t; 23 Node<K,V> e = next; 24 if (modCount != expectedModCount) 25 throw new ConcurrentModificationException(); 26 if (e == null) 27 throw new NoSuchElementException(); 28 if ((next = (current = e).next) == null && (t = table) != null) { 29 do {} while (index < t.length && (next = t[index++]) == null); 30 } 31 return e; 32 } 33
34 public final void remove() { 35 Node<K,V> p = current; 36 if (p == null) 37 throw new IllegalStateException(); 38 if (modCount != expectedModCount) 39 throw new ConcurrentModificationException(); 40 current = null; 41 K key = p.key; 42 removeNode(hash(key), key, null, false, false); 43 expectedModCount = modCount; 44 } 45 } 46
47 final class KeyIterator extends HashIterator 48 implements Iterator<K> { 49 public final K next() { return nextNode().key; } 50 } 51
52 final class ValueIterator extends HashIterator 53 implements Iterator<V> { 54 public final V next() { return nextNode().value; } 55 } 56
57 final class EntryIterator extends HashIterator 58 implements Iterator<Map.Entry<K,V>> { 59 public final Map.Entry<K,V> next() { return nextNode(); } 60 }
廢棄的接口:Enumeration
Enumeration接口是JDK1.0時推出的,是最好的迭代輸出接口,最早使用Vector(現在推薦使用ArrayList)時就是使用Enumeration接口進行輸出。雖然Enumeration是一個舊的類,但是在JDK1.5之后為Enumeration類進行了擴充,增加了泛型的操作應用。
Enumeration接口常用的方法有hasMoreElements()(判斷是否有下一個值)和 nextElement()(取出當前元素),這些方法的功能跟Iterator類似,只是Iterator中存在刪除數據的方法,而此接口不存在刪除操作。
為什么還要繼續使用Enumeration接口
Enumeration和Iterator接口功能相似,而且Iterator的功能還比Enumeration多,那么為什么還要使用Enumeration?這是因為java的發展經歷了很長時間,一些比較古老的系統或者類庫中的方法還在使用Enumeration接口,因此為了兼容,還是需要使用Enumeration。
下面給出HashTable和HashMap的幾種遍歷方式:

1 public class Person { 2 private int age; 3 private String name; 4 private String email; 5 public int getAge() { 6 return age; 7 } 8 public void setAge(int age) { 9 this.age = age; 10 } 11 public String getName() { 12 return name; 13 } 14 public void setName(String name) { 15 this.name = name; 16 } 17 public String getEmail() { 18 return email; 19 } 20 public void setEmail(String email) { 21 this.email = email; 22 } 23 @Override 24 public String toString() { 25 return "Person [age=" + age + ", name=" + name + ", email=" + email + "]"; 26 } 27 }

1 public class Test2 { 2 public static void main(String[] args) { 3 Person person1 = new Person(); 4 person1.setAge(34); 5 person1.setName("Jacky"); 6 person1.setEmail("Jacky@gmail.com"); 7
8 Person person2 = new Person(); 9 person2.setAge(23); 10 person2.setName("Ajay"); 11 person2.setEmail("Ajay@gmail.com"); 12
13 Person person3 = new Person(); 14 person3.setAge(12); 15 person3.setName("Bill"); 16 person3.setEmail("Bill@gmail.com"); 17
18 Person person4 = new Person(); 19 person4.setAge(23); 20 person4.setName("Gace"); 21 person4.setEmail("Gace@gmail.com"); 22
23 Person person5 = new Person(); 24 person5.setAge(45); 25 person5.setName("Jim"); 26 person5.setEmail("Jim@gmail.com"); 27
28 Hashtable<String, Person> ht = new Hashtable<String, Person>(); 29 ht.put("1", person1); 30 ht.put("2", person2); 31 ht.put("3", person3); 32 ht.put("4", person4); 33 ht.put("5", person5); 34
35 HashMap<String, Person> hm = new HashMap<String, Person>(); 36 hm.put("1", person1); 37 hm.put("2", person2); 38 hm.put("3", person3); 39 hm.put("4", person4); 40 hm.put("5", person5); 41
42 //HashTable 遍歷方式: 43 //第一種遍歷方式, 使用key
44 Enumeration<String> keys = ht.keys(); 45 while (keys.hasMoreElements()) { 46 String key = (String) keys.nextElement(); 47 System.out.println("HashTable 的 key 是 : " + key + ", Value 是 : "+ht.get(key)); 48 } 49
50
51 //第二種方式:使用elements()
52 Enumeration<Person> elements = ht.elements(); 53 while (elements.hasMoreElements()) { 54 Person person = (Person) elements.nextElement(); 55 System.out.println(person); 56 } 57
58 //第三種方式:使用keySet()
59 Iterator<String> iterator = ht.keySet().iterator(); 60 while (iterator.hasNext()) { 61 String key = (String) iterator.next(); 62 Person value = hm.get(key); 63
64 System.out.println(key + " " + value); 65 } 66
67 //第四種方式:使用entrySet
68 Iterator<Entry<String, Person>> iterator2 = ht.entrySet().iterator(); 69 while (iterator2.hasNext()) { 70 Map.Entry<String, Person> entry = (Map.Entry<String, Person>) iterator2.next(); 71
72 String key = entry.getKey(); 73 Person value = entry.getValue(); 74
75 System.out.println(key + " " + value); 76 } 77
78 //HashTable 79 //第一種方式
80 Iterator<Entry<String, Person>> iterator3 = hm.entrySet().iterator(); 81 while (iterator3.hasNext()) { 82 Map.Entry<String, Person> entry = (Map.Entry<String, Person>) iterator3.next(); 83
84 String key = entry.getKey(); 85 Person value = entry.getValue(); 86
87 System.out.println(key + " " + value); 88 } 89
90 //第二種方式
91 Iterator<String> iterator4 = hm.keySet().iterator(); 92 // the second method to travel the map
93 while (iterator4.hasNext()) { 94 String key = (String) iterator4.next(); 95 Person value = hm.get(key); 96
97 System.out.println(key + " " + value); 98 } 99 } 100 }
6)HashTable中hash數組默認大小是11,增加的方式是 old*2+1。HashMap中hash數組的默認大小是16,而且一定是2的指數。
HashMap:
1 /**
2 * The default initial capacity - MUST be a power of two. 3 */
4 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
HashTable:通常,默認加載因子是 0.75, 這是在時間和空間成本上尋求一種折衷。加載因子過高雖然減少了空間開銷,但同時也增加了查找某個條目的時間(在大多數 Hashtable 操作中,包括 get 和 put 操作,都反映了這一點)。
1 // 默認構造函數。
2 public Hashtable() { 3 // 默認構造函數,指定的容量大小是11;加載因子是0.75
4 this(11, 0.75f); 5 }
7)哈希值的使用不同
HashTable:,HashTable直接使用對象的hashCode
1 int hash = key.hashCode(); 2 int index = (hash & 0x7FFFFFFF) % tab.length;
HashMap:HashMap重新計算hash值,而且用與代替求模:
1 int hash = hash(k); 2 int i = indexFor(hash, table.length); 3 static int hash(Object x) { 4 h ^= (h >>> 20) ^ (h >>> 12); 5 return h ^ (h >>> 7) ^ (h >>> 4); 6 } 7 static int indexFor(int h, int length) { 8 return h & (length-1); 9 }
3,其他關聯
3.1HashMap與HashSet的關系
a、HashSet底層是采用HashMap實現的:
1 public HashSet() { 2 map = new HashMap<E,Object>(); 3 }
b、調用HashSet的add方法時,實際上是向HashMap中增加了一行(key-value對),該行的key就是向HashSet增加的那個對象,該行的value就是一個Object類型的常量。
1 private static final Object PRESENT = new Object(); public boolean add(E e) { 2 return map.put(e, PRESENT)==null; 3 } 4 public boolean remove(Object o) { 5 return map.remove(o)==PRESENT; 6 }
3.2 HashMap 和 ConcurrentHashMap 的關系
關於這部分內容建議自己去翻翻源碼,ConcurrentHashMap
也是一種線程安全的集合類,他和HashTable
也是有區別的,主要區別就是加鎖的粒度以及如何加鎖,ConcurrentHashMap
的加鎖粒度要比HashTable
更細一點。將數據分成一段一段的存儲,然后給每一段數據配一把鎖,當一個線程占用鎖訪問其中一個段數據的時候,其他段的數據也能被其他線程訪問。
更多請參考: http://www.hollischuang.com/archives/82
4. HashTable源碼奉上

1 package java.util; 2
3 import java.io.*; 4
5 public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, Cloneable, java.io.Serializable { 6
7 // Hashtable保存key-value的數組。 8 // Hashtable是采用拉鏈法實現的,每一個Entry本質上是一個單向鏈表
9 private transient Entry[] table; 10
11 // Hashtable中元素的實際數量
12 private transient int count; 13
14 // 閾值,用於判斷是否需要調整Hashtable的容量(threshold = 容量*加載因子)
15 private int threshold; 16
17 // 加載因子
18 private float loadFactor; 19
20 // Hashtable被改變的次數
21 private transient int modCount = 0; 22
23 // 序列版本號
24 private static final long serialVersionUID = 1421746759512286392L; 25
26 // 指定“容量大小”和“加載因子”的構造函數
27 public Hashtable(int initialCapacity, float loadFactor) { 28 if (initialCapacity < 0) 29 throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); 30 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 31 throw new IllegalArgumentException("Illegal Load: " + loadFactor); 32
33 if (initialCapacity == 0) 34 initialCapacity = 1; 35 this.loadFactor = loadFactor; 36 table = new Entry[initialCapacity]; 37 threshold = (int) (initialCapacity * loadFactor); 38 } 39
40 // 指定“容量大小”的構造函數
41 public Hashtable(int initialCapacity) { 42 this(initialCapacity, 0.75f); 43 } 44
45 // 默認構造函數。
46 public Hashtable() { 47 // 默認構造函數,指定的容量大小是11;加載因子是0.75
48 this(11, 0.75f); 49 } 50
51 // 包含“子Map”的構造函數
52 public Hashtable(Map<? extends K, ? extends V> t) { 53 this(Math.max(2 * t.size(), 11), 0.75f); 54 // 將“子Map”的全部元素都添加到Hashtable中
55 putAll(t); 56 } 57
58 public synchronized int size() { 59 return count; 60 } 61
62 public synchronized boolean isEmpty() { 63 return count == 0; 64 } 65
66 // 返回“所有key”的枚舉對象
67 public synchronized Enumeration<K> keys() { 68 return this.<K>getEnumeration(KEYS); 69 } 70
71 // 返回“所有value”的枚舉對象
72 public synchronized Enumeration<V> elements() { 73 return this.<V>getEnumeration(VALUES); 74 } 75
76 // 判斷Hashtable是否包含“值(value)”
77 public synchronized boolean contains(Object value) { 78 // Hashtable中“鍵值對”的value不能是null, 79 // 若是null的話,拋出異常!
80 if (value == null) { 81 throw new NullPointerException(); 82 } 83
84 // 從后向前遍歷table數組中的元素(Entry) 85 // 對於每個Entry(單向鏈表),逐個遍歷,判斷節點的值是否等於value
86 Entry tab[] = table; 87 for (int i = tab.length; i-- > 0;) { 88 for (Entry<K, V> e = tab[i]; e != null; e = e.next) { 89 if (e.value.equals(value)) { 90 return true; 91 } 92 } 93 } 94 return false; 95 } 96
97 public boolean containsValue(Object value) { 98 return contains(value); 99 } 100
101 // 判斷Hashtable是否包含key
102 public synchronized boolean containsKey(Object key) { 103 Entry tab[] = table; 104 int hash = key.hashCode(); 105 // 計算索引值, 106 // % tab.length 的目的是防止數據越界
107 int index = (hash & 0x7FFFFFFF) % tab.length; 108 // 找到“key對應的Entry(鏈表)”,然后在鏈表中找出“哈希值”和“鍵值”與key都相等的元素
109 for (Entry<K, V> e = tab[index]; e != null; e = e.next) { 110 if ((e.hash == hash) && e.key.equals(key)) { 111 return true; 112 } 113 } 114 return false; 115 } 116
117 // 返回key對應的value,沒有的話返回null
118 public synchronized V get(Object key) { 119 Entry tab[] = table; 120 int hash = key.hashCode(); 121 // 計算索引值,
122 int index = (hash & 0x7FFFFFFF) % tab.length; 123 // 找到“key對應的Entry(鏈表)”,然后在鏈表中找出“哈希值”和“鍵值”與key都相等的元素
124 for (Entry<K, V> e = tab[index]; e != null; e = e.next) { 125 if ((e.hash == hash) && e.key.equals(key)) { 126 return e.value; 127 } 128 } 129 return null; 130 } 131
132 // 調整Hashtable的長度,將長度變成原來的(2倍+1) 133 // (01) 將“舊的Entry數組”賦值給一個臨時變量。 134 // (02) 創建一個“新的Entry數組”,並賦值給“舊的Entry數組” 135 // (03) 將“Hashtable”中的全部元素依次添加到“新的Entry數組”中
136 protected void rehash() { 137 int oldCapacity = table.length; 138 Entry[] oldMap = table; 139
140 int newCapacity = oldCapacity * 2 + 1; 141 Entry[] newMap = new Entry[newCapacity]; 142
143 modCount++; 144 threshold = (int) (newCapacity * loadFactor); 145 table = newMap; 146
147 for (int i = oldCapacity; i-- > 0;) { 148 for (Entry<K, V> old = oldMap[i]; old != null;) { 149 Entry<K, V> e = old; 150 old = old.next; 151
152 int index = (e.hash & 0x7FFFFFFF) % newCapacity; 153 e.next = newMap[index]; 154 newMap[index] = e; 155 } 156 } 157 } 158
159 // 將“key-value”添加到Hashtable中
160 public synchronized V put(K key, V value) { 161 // Hashtable中不能插入value為null的元素!!!
162 if (value == null) { 163 throw new NullPointerException(); 164 } 165
166 // 若“Hashtable中已存在鍵為key的鍵值對”, 167 // 則用“新的value”替換“舊的value”
168 Entry tab[] = table; 169 int hash = key.hashCode(); 170 int index = (hash & 0x7FFFFFFF) % tab.length; 171 for (Entry<K, V> e = tab[index]; e != null; e = e.next) { 172 if ((e.hash == hash) && e.key.equals(key)) { 173 V old = e.value; 174 e.value = value; 175 return old; 176 } 177 } 178
179 // 若“Hashtable中不存在鍵為key的鍵值對”, 180 // (01) 將“修改統計數”+1
181 modCount++; 182 // (02) 若“Hashtable實際容量” > “閾值”(閾值=總的容量 * 加載因子) 183 // 則調整Hashtable的大小
184 if (count >= threshold) { 185 // Rehash the table if the threshold is exceeded
186 rehash(); 187
188 tab = table; 189 index = (hash & 0x7FFFFFFF) % tab.length; 190 } 191
192 // (03) 將“Hashtable中index”位置的Entry(鏈表)保存到e中
193 Entry<K, V> e = tab[index]; 194 // (04) 195 // 創建“新的Entry節點”,並將“新的Entry”插入“Hashtable的index位置”,並設置e為“新的Entry”的下一個元素(即“新Entry”為鏈表表頭)。
196 tab[index] = new Entry<K, V>(hash, key, value, e); 197 // (05) 將“Hashtable的實際容量”+1
198 count++; 199 return null; 200 } 201
202 // 刪除Hashtable中鍵為key的元素
203 public synchronized V remove(Object key) { 204 Entry tab[] = table; 205 int hash = key.hashCode(); 206 int index = (hash & 0x7FFFFFFF) % tab.length; 207 // 找到“key對應的Entry(鏈表)” 208 // 然后在鏈表中找出要刪除的節點,並刪除該節點。
209 for (Entry<K, V> e = tab[index], prev = null; e != null; prev = e, e = e.next) { 210 if ((e.hash == hash) && e.key.equals(key)) { 211 modCount++; 212 if (prev != null) { 213 prev.next = e.next; 214 } else { 215 tab[index] = e.next; 216 } 217 count--; 218 V oldValue = e.value; 219 e.value = null; 220 return oldValue; 221 } 222 } 223 return null; 224 } 225
226 // 將“Map(t)”的中全部元素逐一添加到Hashtable中
227 public synchronized void putAll(Map<? extends K, ? extends V> t) { 228 for (Map.Entry<? extends K, ? extends V> e : t.entrySet()) 229 put(e.getKey(), e.getValue()); 230 } 231
232 // 清空Hashtable 233 // 將Hashtable的table數組的值全部設為null
234 public synchronized void clear() { 235 Entry tab[] = table; 236 modCount++; 237 for (int index = tab.length; --index >= 0;) 238 tab[index] = null; 239 count = 0; 240 } 241
242 // 克隆一個Hashtable,並以Object的形式返回。
243 public synchronized Object clone() { 244 try { 245 Hashtable<K, V> t = (Hashtable<K, V>) super.clone(); 246 t.table = new Entry[table.length]; 247 for (int i = table.length; i-- > 0;) { 248 t.table[i] = (table[i] != null) ? (Entry<K, V>) table[i].clone() : null; 249 } 250 t.keySet = null; 251 t.entrySet = null; 252 t.values = null; 253 t.modCount = 0; 254 return t; 255 } catch (CloneNotSupportedException e) { 256 // this shouldn't happen, since we are Cloneable
257 throw new InternalError(); 258 } 259 } 260
261 public synchronized String toString() { 262 int max = size() - 1; 263 if (max == -1) 264 return "{}"; 265
266 StringBuilder sb = new StringBuilder(); 267 Iterator<Map.Entry<K, V>> it = entrySet().iterator(); 268
269 sb.append('{'); 270 for (int i = 0;; i++) { 271 Map.Entry<K, V> e = it.next(); 272 K key = e.getKey(); 273 V value = e.getValue(); 274 sb.append(key == this ? "(this Map)" : key.toString()); 275 sb.append('='); 276 sb.append(value == this ? "(this Map)" : value.toString()); 277
278 if (i == max) 279 return sb.append('}').toString(); 280 sb.append(", "); 281 } 282 } 283
284 // 獲取Hashtable的枚舉類對象 285 // 若Hashtable的實際大小為0,則返回“空枚舉類”對象; 286 // 否則,返回正常的Enumerator的對象。(Enumerator實現了迭代器和枚舉兩個接口)
287 private <T> Enumeration<T> getEnumeration(int type) { 288 if (count == 0) { 289 return (Enumeration<T>) emptyEnumerator; 290 } else { 291 return new Enumerator<T>(type, false); 292 } 293 } 294
295 // 獲取Hashtable的迭代器 296 // 若Hashtable的實際大小為0,則返回“空迭代器”對象; 297 // 否則,返回正常的Enumerator的對象。(Enumerator實現了迭代器和枚舉兩個接口)
298 private <T> Iterator<T> getIterator(int type) { 299 if (count == 0) { 300 return (Iterator<T>) emptyIterator; 301 } else { 302 return new Enumerator<T>(type, true); 303 } 304 } 305
306 // Hashtable的“key的集合”。它是一個Set,意味着沒有重復元素
307 private transient volatile Set<K> keySet = null; 308 // Hashtable的“key-value的集合”。它是一個Set,意味着沒有重復元素
309 private transient volatile Set<Map.Entry<K, V>> entrySet = null; 310 // Hashtable的“key-value的集合”。它是一個Collection,意味着可以有重復元素
311 private transient volatile Collection<V> values = null; 312
313 // 返回一個被synchronizedSet封裝后的KeySet對象 314 // synchronizedSet封裝的目的是對KeySet的所有方法都添加synchronized,實現多線程同步
315 public Set<K> keySet() { 316 if (keySet == null) 317 keySet = Collections.synchronizedSet(new KeySet(), this); 318 return keySet; 319 } 320
321 // Hashtable的Key的Set集合。 322 // KeySet繼承於AbstractSet,所以,KeySet中的元素沒有重復的。
323 private class KeySet extends AbstractSet<K> { 324 public Iterator<K> iterator() { 325 return getIterator(KEYS); 326 } 327
328 public int size() { 329 return count; 330 } 331
332 public boolean contains(Object o) { 333 return containsKey(o); 334 } 335
336 public boolean remove(Object o) { 337 return Hashtable.this.remove(o) != null; 338 } 339
340 public void clear() { 341 Hashtable.this.clear(); 342 } 343 } 344
345 // 返回一個被synchronizedSet封裝后的EntrySet對象 346 // synchronizedSet封裝的目的是對EntrySet的所有方法都添加synchronized,實現多線程同步
347 public Set<Map.Entry<K, V>> entrySet() { 348 if (entrySet == null) 349 entrySet = Collections.synchronizedSet(new EntrySet(), this); 350 return entrySet; 351 } 352
353 // Hashtable的Entry的Set集合。 354 // EntrySet繼承於AbstractSet,所以,EntrySet中的元素沒有重復的。
355 private class EntrySet extends AbstractSet<Map.Entry<K, V>> { 356 public Iterator<Map.Entry<K, V>> iterator() { 357 return getIterator(ENTRIES); 358 } 359
360 public boolean add(Map.Entry<K, V> o) { 361 return super.add(o); 362 } 363
364 // 查找EntrySet中是否包含Object(0) 365 // 首先,在table中找到o對應的Entry(Entry是一個單向鏈表) 366 // 然后,查找Entry鏈表中是否存在Object
367 public boolean contains(Object o) { 368 if (!(o instanceof Map.Entry)) 369 return false; 370 Map.Entry entry = (Map.Entry) o; 371 Object key = entry.getKey(); 372 Entry[] tab = table; 373 int hash = key.hashCode(); 374 int index = (hash & 0x7FFFFFFF) % tab.length; 375
376 for (Entry e = tab[index]; e != null; e = e.next) 377 if (e.hash == hash && e.equals(entry)) 378 return true; 379 return false; 380 } 381
382 // 刪除元素Object(0) 383 // 首先,在table中找到o對應的Entry(Entry是一個單向鏈表) 384 // 然后,刪除鏈表中的元素Object
385 public boolean remove(Object o) { 386 if (!(o instanceof Map.Entry)) 387 return false; 388 Map.Entry<K, V> entry = (Map.Entry<K, V>) o; 389 K key = entry.getKey(); 390 Entry[] tab = table; 391 int hash = key.hashCode(); 392 int index = (hash & 0x7FFFFFFF) % tab.length; 393
394 for (Entry<K, V> e = tab[index], prev = null; e != null; prev = e, e = e.next) { 395 if (e.hash == hash && e.equals(entry)) { 396 modCount++; 397 if (prev != null) 398 prev.next = e.next; 399 else
400 tab[index] = e.next; 401
402 count--; 403 e.value = null; 404 return true; 405 } 406 } 407 return false; 408 } 409
410 public int size() { 411 return count; 412 } 413
414 public void clear() { 415 Hashtable.this.clear(); 416 } 417 } 418
419 // 返回一個被synchronizedCollection封裝后的ValueCollection對象 420 // synchronizedCollection封裝的目的是對ValueCollection的所有方法都添加synchronized,實現多線程同步
421 public Collection<V> values() { 422 if (values == null) 423 values = Collections.synchronizedCollection(new ValueCollection(), this); 424 return values; 425 } 426
427 // Hashtable的value的Collection集合。 428 // ValueCollection繼承於AbstractCollection,所以,ValueCollection中的元素可以重復的。
429 private class ValueCollection extends AbstractCollection<V> { 430 public Iterator<V> iterator() { 431 return getIterator(VALUES); 432 } 433
434 public int size() { 435 return count; 436 } 437
438 public boolean contains(Object o) { 439 return containsValue(o); 440 } 441
442 public void clear() { 443 Hashtable.this.clear(); 444 } 445 } 446
447 // 重新equals()函數 448 // 若兩個Hashtable的所有key-value鍵值對都相等,則判斷它們兩個相等
449 public synchronized boolean equals(Object o) { 450 if (o == this) 451 return true; 452
453 if (!(o instanceof Map)) 454 return false; 455 Map<K, V> t = (Map<K, V>) o; 456 if (t.size() != size()) 457 return false; 458
459 try { 460 // 通過迭代器依次取出當前Hashtable的key-value鍵值對 461 // 並判斷該鍵值對,存在於Hashtable(o)中。 462 // 若不存在,則立即返回false;否則,遍歷完“當前Hashtable”並返回true。
463 Iterator<Map.Entry<K, V>> i = entrySet().iterator(); 464 while (i.hasNext()) { 465 Map.Entry<K, V> e = i.next(); 466 K key = e.getKey(); 467 V value = e.getValue(); 468 if (value == null) { 469 if (!(t.get(key) == null && t.containsKey(key))) 470 return false; 471 } else { 472 if (!value.equals(t.get(key))) 473 return false; 474 } 475 } 476 } catch (ClassCastException unused) { 477 return false; 478 } catch (NullPointerException unused) { 479 return false; 480 } 481
482 return true; 483 } 484
485 // 計算Hashtable的哈希值 486 // 若 Hashtable的實際大小為0 或者 加載因子<0,則返回0。 487 // 否則,返回“Hashtable中的每個Entry的key和value的異或值 的總和”。
488 public synchronized int hashCode() { 489 int h = 0; 490 if (count == 0 || loadFactor < 0) 491 return h; // Returns zero
492
493 loadFactor = -loadFactor; // Mark hashCode computation in progress
494 Entry[] tab = table; 495 for (int i = 0; i < tab.length; i++) 496 for (Entry e = tab[i]; e != null; e = e.next) 497 h += e.key.hashCode() ^ e.value.hashCode(); 498 loadFactor = -loadFactor; // Mark hashCode computation complete
499
500 return h; 501 } 502
503 // java.io.Serializable的寫入函數 504 // 將Hashtable的“總的容量,實際容量,所有的Entry”都寫入到輸出流中
505 private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { 506 // Write out the length, threshold, loadfactor
507 s.defaultWriteObject(); 508
509 // Write out length, count of elements and then the key/value objects
510 s.writeInt(table.length); 511 s.writeInt(count); 512 for (int index = table.length - 1; index >= 0; index--) { 513 Entry entry = table[index]; 514
515 while (entry != null) { 516 s.writeObject(entry.key); 517 s.writeObject(entry.value); 518 entry = entry.next; 519 } 520 } 521 } 522
523 // java.io.Serializable的讀取函數:根據寫入方式讀出 524 // 將Hashtable的“總的容量,實際容量,所有的Entry”依次讀出
525 private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { 526 // Read in the length, threshold, and loadfactor
527 s.defaultReadObject(); 528
529 // Read the original length of the array and number of elements
530 int origlength = s.readInt(); 531 int elements = s.readInt(); 532
533 // Compute new size with a bit of room 5% to grow but 534 // no larger than the original size. Make the length 535 // odd if it's large enough, this helps distribute the entries. 536 // Guard against the length ending up zero, that's not valid.
537 int length = (int) (elements * loadFactor) + (elements / 20) + 3; 538 if (length > elements && (length & 1) == 0) 539 length--; 540 if (origlength > 0 && length > origlength) 541 length = origlength; 542
543 Entry[] table = new Entry[length]; 544 count = 0; 545
546 // Read the number of elements and then all the key/value objects
547 for (; elements > 0; elements--) { 548 K key = (K) s.readObject(); 549 V value = (V) s.readObject(); 550 // synch could be eliminated for performance
551 reconstitutionPut(table, key, value); 552 } 553 this.table = table; 554 } 555
556 private void reconstitutionPut(Entry[] tab, K key, V value) throws StreamCorruptedException { 557 if (value == null) { 558 throw new java.io.StreamCorruptedException(); 559 } 560 // Makes sure the key is not already in the hashtable. 561 // This should not happen in deserialized version.
562 int hash = key.hashCode(); 563 int index = (hash & 0x7FFFFFFF) % tab.length; 564 for (Entry<K, V> e = tab[index]; e != null; e = e.next) { 565 if ((e.hash == hash) && e.key.equals(key)) { 566 throw new java.io.StreamCorruptedException(); 567 } 568 } 569 // Creates the new entry.
570 Entry<K, V> e = tab[index]; 571 tab[index] = new Entry<K, V>(hash, key, value, e); 572 count++; 573 } 574
575 // Hashtable的Entry節點,它本質上是一個單向鏈表。 576 // 也因此,我們才能推斷出Hashtable是由拉鏈法實現的散列表
577 private static class Entry<K, V> implements Map.Entry<K, V> { 578 // 哈希值
579 int hash; 580 K key; 581 V value; 582 // 指向的下一個Entry,即鏈表的下一個節點
583 Entry<K, V> next; 584
585 // 構造函數
586 protected Entry(int hash, K key, V value, Entry<K, V> next) { 587 this.hash = hash; 588 this.key = key; 589 this.value = value; 590 this.next = next; 591 } 592
593 protected Object clone() { 594 return new Entry<K, V>(hash, key, value, (next == null ? null : (Entry<K, V>) next.clone())); 595 } 596
597 public K getKey() { 598 return key; 599 } 600
601 public V getValue() { 602 return value; 603 } 604
605 // 設置value。若value是null,則拋出異常。
606 public V setValue(V value) { 607 if (value == null) 608 throw new NullPointerException(); 609
610 V oldValue = this.value; 611 this.value = value; 612 return oldValue; 613 } 614
615 // 覆蓋equals()方法,判斷兩個Entry是否相等。 616 // 若兩個Entry的key和value都相等,則認為它們相等。
617 public boolean equals(Object o) { 618 if (!(o instanceof Map.Entry)) 619 return false; 620 Map.Entry e = (Map.Entry) o; 621
622 return (key == null ? e.getKey() == null : key.equals(e.getKey())) 623 && (value == null ? e.getValue() == null : value.equals(e.getValue())); 624 } 625
626 public int hashCode() { 627 return hash ^ (value == null ? 0 : value.hashCode()); 628 } 629
630 public String toString() { 631 return key.toString() + "=" + value.toString(); 632 } 633 } 634
635 private static final int KEYS = 0; 636 private static final int VALUES = 1; 637 private static final int ENTRIES = 2; 638
639 // Enumerator的作用是提供了“通過elements()遍歷Hashtable的接口” 和 640 // “通過entrySet()遍歷Hashtable的接口”。因為,它同時實現了 “Enumerator接口”和“Iterator接口”。
641 private class Enumerator<T> implements Enumeration<T>, Iterator<T> { 642 // 指向Hashtable的table
643 Entry[] table = Hashtable.this.table; 644 // Hashtable的總的大小
645 int index = table.length; 646 Entry<K, V> entry = null; 647 Entry<K, V> lastReturned = null; 648 int type; 649
650 // Enumerator是 “迭代器(Iterator)” 還是 “枚舉類(Enumeration)”的標志 651 // iterator為true,表示它是迭代器;否則,是枚舉類。
652 boolean iterator; 653
654 // 在將Enumerator當作迭代器使用時會用到,用來實現fail-fast機制。
655 protected int expectedModCount = modCount; 656
657 Enumerator(int type, boolean iterator) { 658 this.type = type; 659 this.iterator = iterator; 660 } 661
662 // 從遍歷table的數組的末尾向前查找,直到找到不為null的Entry。
663 public boolean hasMoreElements() { 664 Entry<K, V> e = entry; 665 int i = index; 666 Entry[] t = table; 667 /* Use locals for faster loop iteration */
668 while (e == null && i > 0) { 669 e = t[--i]; 670 } 671 entry = e; 672 index = i; 673 return e != null; 674 } 675
676 // 獲取下一個元素 677 // 注意:從hasMoreElements() 和nextElement() 可以看出“Hashtable的elements()遍歷方式” 678 // 首先,從后向前的遍歷table數組。table數組的每個節點都是一個單向鏈表(Entry)。 679 // 然后,依次向后遍歷單向鏈表Entry。
680 public T nextElement() { 681 Entry<K, V> et = entry; 682 int i = index; 683 Entry[] t = table; 684 /* Use locals for faster loop iteration */
685 while (et == null && i > 0) { 686 et = t[--i]; 687 } 688 entry = et; 689 index = i; 690 if (et != null) { 691 Entry<K, V> e = lastReturned = entry; 692 entry = e.next; 693 return type == KEYS ? (T) e.key : (type == VALUES ? (T) e.value : (T) e); 694 } 695 throw new NoSuchElementException("Hashtable Enumerator"); 696 } 697
698 // 迭代器Iterator的判斷是否存在下一個元素 699 // 實際上,它是調用的hasMoreElements()
700 public boolean hasNext() { 701 return hasMoreElements(); 702 } 703
704 // 迭代器獲取下一個元素 705 // 實際上,它是調用的nextElement()
706 public T next() { 707 if (modCount != expectedModCount) 708 throw new ConcurrentModificationException(); 709 return nextElement(); 710 } 711
712 // 迭代器的remove()接口。 713 // 首先,它在table數組中找出要刪除元素所在的Entry, 714 // 然后,刪除單向鏈表Entry中的元素。
715 public void remove() { 716 if (!iterator) 717 throw new UnsupportedOperationException(); 718 if (lastReturned == null) 719 throw new IllegalStateException("Hashtable Enumerator"); 720 if (modCount != expectedModCount) 721 throw new ConcurrentModificationException(); 722
723 synchronized (Hashtable.this) { 724 Entry[] tab = Hashtable.this.table; 725 int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; 726
727 for (Entry<K, V> e = tab[index], prev = null; e != null; prev = e, e = e.next) { 728 if (e == lastReturned) { 729 modCount++; 730 expectedModCount++; 731 if (prev == null) 732 tab[index] = e.next; 733 else
734 prev.next = e.next; 735 count--; 736 lastReturned = null; 737 return; 738 } 739 } 740 throw new ConcurrentModificationException(); 741 } 742 } 743 } 744
745 private static Enumeration emptyEnumerator = new EmptyEnumerator(); 746 private static Iterator emptyIterator = new EmptyIterator(); 747
748 // 空枚舉類 749 // 當Hashtable的實際大小為0;此時,又要通過Enumeration遍歷Hashtable時,返回的是“空枚舉類”的對象。
750 private static class EmptyEnumerator implements Enumeration<Object> { 751
752 EmptyEnumerator() { 753 } 754
755 // 空枚舉類的hasMoreElements() 始終返回false
756 public boolean hasMoreElements() { 757 return false; 758 } 759
760 // 空枚舉類的nextElement() 拋出異常
761 public Object nextElement() { 762 throw new NoSuchElementException("Hashtable Enumerator"); 763 } 764 } 765
766 // 空迭代器 767 // 當Hashtable的實際大小為0;此時,又要通過迭代器遍歷Hashtable時,返回的是“空迭代器”的對象。
768 private static class EmptyIterator implements Iterator<Object> { 769
770 EmptyIterator() { 771 } 772
773 public boolean hasNext() { 774 return false; 775 } 776
777 public Object next() { 778 throw new NoSuchElementException("Hashtable Iterator"); 779 } 780
781 public void remove() { 782 throw new IllegalStateException("Hashtable Iterator"); 783 } 784
785 } 786 }