前言:
又是一個大好的周末, 可惜今天起來有點晚, 扒開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 }
View Code
然後是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 }
Person.java
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("[email protected]");
7
8 Person person2 = new Person();
9 person2.setAge(23);
10 person2.setName("Ajay");
11 person2.setEmail("[email protected]");
12
13 Person person3 = new Person();
14 person3.setAge(12);
15 person3.setName("Bill");
16 person3.setEmail("[email protected]");
17
18 Person person4 = new Person();
19 person4.setAge(23);
20 person4.setName("Gace");
21 person4.setEmail("[email protected]");
22
23 Person person5 = new Person();
24 person5.setAge(45);
25 person5.setName("Jim");
26 person5.setEmail("[email protected]");
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 }
Test.java
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 }