天天看點

[源碼解析]HashMap和HashTable的差別(源碼分析解讀)

前言: 

又是一個大好的周末, 可惜今天起來有點晚, 扒開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的差別(源碼分析解讀)

可以看到, 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和HashTable的差別(源碼分析解讀)

 HashMap:

[源碼解析]HashMap和HashTable的差別(源碼分析解讀)

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的方法:

[源碼解析]HashMap和HashTable的差別(源碼分析解讀)
[源碼解析]HashMap和HashTable的差別(源碼分析解讀)

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中:

[源碼解析]HashMap和HashTable的差別(源碼分析解讀)
[源碼解析]HashMap和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中:

[源碼解析]HashMap和HashTable的差別(源碼分析解讀)
[源碼解析]HashMap和HashTable的差別(源碼分析解讀)
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的幾種周遊方式:

[源碼解析]HashMap和HashTable的差別(源碼分析解讀)
[源碼解析]HashMap和HashTable的差別(源碼分析解讀)
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

[源碼解析]HashMap和HashTable的差別(源碼分析解讀)
[源碼解析]HashMap和HashTable的差別(源碼分析解讀)
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源碼奉上

[源碼解析]HashMap和HashTable的差別(源碼分析解讀)
[源碼解析]HashMap和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 }