[源碼解析]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輸出的順序卻有些詭異.

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     }
View Code

廢棄的接口: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("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 }
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 }
View Code

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM