Java 集合系列11之 Hashtable詳細介紹(源碼解析)和使用示例


 

概要

前一章,我們學習了HashMap。這一章,我們對Hashtable進行學習。
我們先對Hashtable有個整體認識,然后再學習它的源碼,最后再通過實例來學會使用Hashtable。
第1部分 Hashtable介紹
第2部分 Hashtable數據結構
第3部分 Hashtable源碼解析(基於JDK1.6.0_45)
第4部分 Hashtable遍歷方式
第5部分 Hashtable示例

轉載請注明出處:http://www.cnblogs.com/skywang12345/p/3310887.html

 

第1部分 Hashtable介紹

Hashtable 簡介

HashMap一樣,Hashtable 也是一個散列表,它存儲的內容是鍵值對(key-value)映射
Hashtable 繼承於Dictionary,實現了Map、Cloneable、java.io.Serializable接口。
Hashtable 的函數都是同步的,這意味着它是線程安全的。它的key、value都不可以為null。此外,Hashtable中的映射不是有序的。

Hashtable 的實例有兩個參數影響其性能:初始容量加載因子。容量 是哈希表中桶 的數量,初始容量 就是哈希表創建時的容量。注意,哈希表的狀態為 open:在發生“哈希沖突”的情況下,單個桶會存儲多個條目,這些條目必須按順序搜索。加載因子 是對哈希表在其容量自動增加之前可以達到多滿的一個尺度。初始容量和加載因子這兩個參數只是對該實現的提示。關於何時以及是否調用 rehash 方法的具體細節則依賴於該實現。
通常,默認加載因子是 0.75, 這是在時間和空間成本上尋求一種折衷。加載因子過高雖然減少了空間開銷,但同時也增加了查找某個條目的時間(在大多數 Hashtable 操作中,包括 get 和 put 操作,都反映了這一點)。

 

Hashtable的構造函數

// 默認構造函數。
public Hashtable() 

// 指定“容量大小”的構造函數
public Hashtable(int initialCapacity) 

// 指定“容量大小”和“加載因子”的構造函數
public Hashtable(int initialCapacity, float loadFactor) 

// 包含“子Map”的構造函數
public Hashtable(Map<? extends K, ? extends V> t)

 

Hashtable的API

synchronized void                clear()
synchronized Object              clone()
             boolean             contains(Object value)
synchronized boolean             containsKey(Object key)
synchronized boolean             containsValue(Object value)
synchronized Enumeration<V>      elements()
synchronized Set<Entry<K, V>>    entrySet()
synchronized boolean             equals(Object object)
synchronized V                   get(Object key)
synchronized int                 hashCode()
synchronized boolean             isEmpty()
synchronized Set<K>              keySet()
synchronized Enumeration<K>      keys()
synchronized V                   put(K key, V value)
synchronized void                putAll(Map<? extends K, ? extends V> map)
synchronized V                   remove(Object key)
synchronized int                 size()
synchronized String              toString()
synchronized Collection<V>       values()

 

第2部分 Hashtable數據結構

Hashtable的繼承關系

java.lang.Object
   ↳     java.util.Dictionary<K, V>
         ↳     java.util.Hashtable<K, V>

public class Hashtable<K,V> extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable { }

 

Hashtable與Map關系如下圖:

從圖中可以看出:
(01) Hashtable繼承於Dictionary類,實現了Map接口。Map是"key-value鍵值對"接口,Dictionary是聲明了操作"鍵值對"函數接口的抽象類。
(02) Hashtable是通過"拉鏈法"實現的哈希表。它包括幾個重要的成員變量:table, count, threshold, loadFactor, modCount
  table是一個Entry[]數組類型,而Entry實際上就是一個單向鏈表。哈希表的"key-value鍵值對"都是存儲在Entry數組中的。
  count是Hashtable的大小,它是Hashtable保存的鍵值對的數量。
  threshold是Hashtable的閾值,用於判斷是否需要調整Hashtable的容量。threshold的值="容量*加載因子"。
  loadFactor就是加載因子。
  modCount是用來實現fail-fast機制的

 

第3部分 Hashtable源碼解析(基於JDK1.6.0_45)

為了更了解Hashtable的原理,下面對Hashtable源碼代碼作出分析。
在閱讀源碼時,建議參考后面的說明來建立對Hashtable的整體認識,這樣更容易理解Hashtable。

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

說明在詳細介紹Hashtable的代碼之前,我們需要了解:和Hashmap一樣,Hashtable也是一個散列表,它也是通過“拉鏈法”解決哈希沖突的。


第3.1部分 Hashtable的“拉鏈法”相關內容

3.1.1 Hashtable數據存儲數組

private transient Entry[] table;

Hashtable中的key-value都是存儲在table數組中的

3.1.2 數據節點Entry的數據結構

 1 private static class Entry<K,V> implements Map.Entry<K,V> {
 2     // 哈希值
 3     int hash;
 4     K key;
 5     V value;
 6     // 指向的下一個Entry,即鏈表的下一個節點
 7     Entry<K,V> next;
 8 
 9     // 構造函數
10     protected Entry(int hash, K key, V value, Entry<K,V> next) {
11         this.hash = hash;
12         this.key = key;
13         this.value = value;
14         this.next = next;
15     }
16 
17     protected Object clone() {
18         return new Entry<K,V>(hash, key, value,
19               (next==null ? null : (Entry<K,V>) next.clone()));
20     }
21 
22     public K getKey() {
23         return key;
24     }
25 
26     public V getValue() {
27         return value;
28     }
29 
30     // 設置value。若value是null,則拋出異常。
31     public V setValue(V value) {
32         if (value == null)
33             throw new NullPointerException();
34 
35         V oldValue = this.value;
36         this.value = value;
37         return oldValue;
38     }
39 
40     // 覆蓋equals()方法,判斷兩個Entry是否相等。
41     // 若兩個Entry的key和value都相等,則認為它們相等。
42     public boolean equals(Object o) {
43         if (!(o instanceof Map.Entry))
44             return false;
45         Map.Entry e = (Map.Entry)o;
46 
47         return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
48            (value==null ? e.getValue()==null : value.equals(e.getValue()));
49     }
50 
51     public int hashCode() {
52         return hash ^ (value==null ? 0 : value.hashCode());
53     }
54 
55     public String toString() {
56         return key.toString()+"="+value.toString();
57     }
58 }
View Code

從中,我們可以看出 Entry 實際上就是一個單向鏈表。這也是為什么我們說Hashtable是通過拉鏈法解決哈希沖突的。
Entry 實現了Map.Entry 接口,即實現getKey(), getValue(), setValue(V value), equals(Object o), hashCode()這些函數。這些都是基本的讀取/修改key、value值的函數。

 

第3.2部分 Hashtable的構造函數

Hashtable共包括4個構造函數

 1 // 默認構造函數。
 2 public Hashtable() {
 3     // 默認構造函數,指定的容量大小是11;加載因子是0.75
 4     this(11, 0.75f);
 5 }
 6 
 7 // 指定“容量大小”的構造函數
 8 public Hashtable(int initialCapacity) {
 9     this(initialCapacity, 0.75f);
10 }
11 
12 // 指定“容量大小”和“加載因子”的構造函數
13 public Hashtable(int initialCapacity, float loadFactor) {
14     if (initialCapacity < 0)
15         throw new IllegalArgumentException("Illegal Capacity: "+
16                                            initialCapacity);
17     if (loadFactor <= 0 || Float.isNaN(loadFactor))
18         throw new IllegalArgumentException("Illegal Load: "+loadFactor);
19 
20     if (initialCapacity==0)
21         initialCapacity = 1;
22     this.loadFactor = loadFactor;
23     table = new Entry[initialCapacity];
24     threshold = (int)(initialCapacity * loadFactor);
25 }
26 
27 // 包含“子Map”的構造函數
28 public Hashtable(Map<? extends K, ? extends V> t) {
29     this(Math.max(2*t.size(), 11), 0.75f);
30     // 將“子Map”的全部元素都添加到Hashtable中
31     putAll(t);
32 }
View Code

 

第3.3部分 Hashtable的主要對外接口

3.3.1 clear()

clear() 的作用是清空Hashtable。它是將Hashtable的table數組的值全部設為null

1 public synchronized void clear() {
2     Entry tab[] = table;
3     modCount++;
4     for (int index = tab.length; --index >= 0; )
5         tab[index] = null;
6     count = 0;
7 }
View Code

3.3.2 contains()containsValue()

contains() 和 containsValue() 的作用都是判斷Hashtable是否包含“值(value)”

 1 public boolean containsValue(Object value) {
 2     return contains(value);
 3 }
 4 
 5 public synchronized boolean contains(Object value) {
 6     // Hashtable中“鍵值對”的value不能是null,
 7     // 若是null的話,拋出異常!
 8     if (value == null) {
 9         throw new NullPointerException();
10     }
11 
12     // 從后向前遍歷table數組中的元素(Entry)
13     // 對於每個Entry(單向鏈表),逐個遍歷,判斷節點的值是否等於value
14     Entry tab[] = table;
15     for (int i = tab.length ; i-- > 0 ;) {
16         for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
17             if (e.value.equals(value)) {
18                 return true;
19             }
20         }
21     }
22     return false;
23 }
View Code

3.3.3 containsKey()

containsKey() 的作用是判斷Hashtable是否包含key

 1 public synchronized boolean containsKey(Object key) {
 2     Entry tab[] = table;
 3     int hash = key.hashCode();
 4     // 計算索引值,
 5     // % tab.length 的目的是防止數據越界
 6     int index = (hash & 0x7FFFFFFF) % tab.length;
 7     // 找到“key對應的Entry(鏈表)”,然后在鏈表中找出“哈希值”和“鍵值”與key都相等的元素
 8     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
 9         if ((e.hash == hash) && e.key.equals(key)) {
10             return true;
11         }
12     }
13     return false;
14 }
View Code

3.3.4 elements()

elements() 的作用是返回“所有value”的枚舉對象

 1 public synchronized Enumeration<V> elements() {
 2     return this.<V>getEnumeration(VALUES);
 3 }
 4 
 5 // 獲取Hashtable的枚舉類對象
 6 private <T> Enumeration<T> getEnumeration(int type) {
 7     if (count == 0) {
 8         return (Enumeration<T>)emptyEnumerator;
 9     } else {
10         return new Enumerator<T>(type, false);
11     }
12 }
View Code

從中,我們可以看出:
(01) 若Hashtable的實際大小為0,則返回“空枚舉類”對象emptyEnumerator;
(02) 否則,返回正常的Enumerator的對象。(Enumerator實現了迭代器和枚舉兩個接口)

我們先看看emptyEnumerator對象是如何實現的

 1 private static Enumeration emptyEnumerator = new EmptyEnumerator();
 2 
 3 // 空枚舉類
 4 // 當Hashtable的實際大小為0;此時,又要通過Enumeration遍歷Hashtable時,返回的是“空枚舉類”的對象。
 5 private static class EmptyEnumerator implements Enumeration<Object> {
 6 
 7     EmptyEnumerator() {
 8     }
 9 
10     // 空枚舉類的hasMoreElements() 始終返回false
11     public boolean hasMoreElements() {
12         return false;
13     }
14 
15     // 空枚舉類的nextElement() 拋出異常
16     public Object nextElement() {
17         throw new NoSuchElementException("Hashtable Enumerator");
18     }
19 }
View Code

我們在來看看Enumeration類

Enumerator的作用是提供了“通過elements()遍歷Hashtable的接口” 和 “通過entrySet()遍歷Hashtable的接口”。因為,它同時實現了 “Enumerator接口”和“Iterator接口”。

  1 private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
  2     // 指向Hashtable的table
  3     Entry[] table = Hashtable.this.table;
  4     // Hashtable的總的大小
  5     int index = table.length;
  6     Entry<K,V> entry = null;
  7     Entry<K,V> lastReturned = null;
  8     int type;
  9 
 10     // Enumerator是 “迭代器(Iterator)” 還是 “枚舉類(Enumeration)”的標志
 11     // iterator為true,表示它是迭代器;否則,是枚舉類。
 12     boolean iterator;
 13 
 14     // 在將Enumerator當作迭代器使用時會用到,用來實現fail-fast機制。
 15     protected int expectedModCount = modCount;
 16 
 17     Enumerator(int type, boolean iterator) {
 18         this.type = type;
 19         this.iterator = iterator;
 20     }
 21 
 22     // 從遍歷table的數組的末尾向前查找,直到找到不為null的Entry。
 23     public boolean hasMoreElements() {
 24         Entry<K,V> e = entry;
 25         int i = index;
 26         Entry[] t = table;
 27         /* Use locals for faster loop iteration */
 28         while (e == null && i > 0) {
 29             e = t[--i];
 30         }
 31         entry = e;
 32         index = i;
 33         return e != null;
 34     }
 35 
 36     // 獲取下一個元素
 37     // 注意:從hasMoreElements() 和nextElement() 可以看出“Hashtable的elements()遍歷方式”
 38     // 首先,從后向前的遍歷table數組。table數組的每個節點都是一個單向鏈表(Entry)。
 39     // 然后,依次向后遍歷單向鏈表Entry。
 40     public T nextElement() {
 41         Entry<K,V> 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<K,V> 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的判斷是否存在下一個元素
 59     // 實際上,它是調用的hasMoreElements()
 60     public boolean hasNext() {
 61         return hasMoreElements();
 62     }
 63 
 64     // 迭代器獲取下一個元素
 65     // 實際上,它是調用的nextElement()
 66     public T next() {
 67         if (modCount != expectedModCount)
 68             throw new ConcurrentModificationException();
 69         return nextElement();
 70     }
 71 
 72     // 迭代器的remove()接口。
 73     // 首先,它在table數組中找出要刪除元素所在的Entry,
 74     // 然后,刪除單向鏈表Entry中的元素。
 75     public void remove() {
 76         if (!iterator)
 77             throw new UnsupportedOperationException();
 78         if (lastReturned == null)
 79             throw new IllegalStateException("Hashtable Enumerator");
 80         if (modCount != expectedModCount)
 81             throw new ConcurrentModificationException();
 82 
 83         synchronized(Hashtable.this) {
 84             Entry[] tab = Hashtable.this.table;
 85             int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
 86 
 87             for (Entry<K,V> e = tab[index], prev = null; e != null;
 88                  prev = e, e = e.next) {
 89                 if (e == lastReturned) {
 90                     modCount++;
 91                     expectedModCount++;
 92                     if (prev == null)
 93                         tab[index] = e.next;
 94                     else
 95                         prev.next = e.next;
 96                     count--;
 97                     lastReturned = null;
 98                     return;
 99                 }
100             }
101             throw new ConcurrentModificationException();
102         }
103     }
104 }
View Code

entrySet(), keySet(), keys(), values()的實現方法和elements()差不多,而且源碼中已經明確的給出了注釋。這里就不再做過多說明了。

3.3.5 get()

get() 的作用就是獲取key對應的value,沒有的話返回null

 1 public synchronized V get(Object key) {
 2     Entry tab[] = table;
 3     int hash = key.hashCode();
 4     // 計算索引值,
 5     int index = (hash & 0x7FFFFFFF) % tab.length;
 6     // 找到“key對應的Entry(鏈表)”,然后在鏈表中找出“哈希值”和“鍵值”與key都相等的元素
 7     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
 8         if ((e.hash == hash) && e.key.equals(key)) {
 9             return e.value;
10         }
11     }
12     return null;
13 }
View Code

3.3.6 put()

put() 的作用是對外提供接口,讓Hashtable對象可以通過put()將“key-value”添加到Hashtable中。

 1 public synchronized V put(K key, V value) {
 2     // Hashtable中不能插入value為null的元素!!!
 3     if (value == null) {
 4         throw new NullPointerException();
 5     }
 6 
 7     // 若“Hashtable中已存在鍵為key的鍵值對”,
 8     // 則用“新的value”替換“舊的value”
 9     Entry tab[] = table;
10     int hash = key.hashCode();
11     int index = (hash & 0x7FFFFFFF) % tab.length;
12     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
13         if ((e.hash == hash) && e.key.equals(key)) {
14             V old = e.value;
15             e.value = value;
16             return old;
17             }
18     }
19 
20     // 若“Hashtable中不存在鍵為key的鍵值對”,
21     // (01) 將“修改統計數”+1
22     modCount++;
23     // (02) 若“Hashtable實際容量” > “閾值”(閾值=總的容量 * 加載因子)
24     //  則調整Hashtable的大小
25     if (count >= threshold) {
26         // Rehash the table if the threshold is exceeded
27         rehash();
28 
29         tab = table;
30         index = (hash & 0x7FFFFFFF) % tab.length;
31     }
32 
33     // (03) 將“Hashtable中index”位置的Entry(鏈表)保存到e中
34     Entry<K,V> e = tab[index];
35     // (04) 創建“新的Entry節點”,並將“新的Entry”插入“Hashtable的index位置”,並設置e為“新的Entry”的下一個元素(即“新Entry”為鏈表表頭)。        
36     tab[index] = new Entry<K,V>(hash, key, value, e);
37     // (05) 將“Hashtable的實際容量”+1
38     count++;
39     return null;
40 }
View Code

3.3.7 putAll()

putAll() 的作用是將“Map(t)”的中全部元素逐一添加到Hashtable中

1 public synchronized void putAll(Map<? extends K, ? extends V> t) {
2     for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
3         put(e.getKey(), e.getValue());
4 }
View Code

3.3.8 remove()

remove() 的作用就是刪除Hashtable中鍵為key的元素

 1 public synchronized V remove(Object key) {
 2     Entry tab[] = table;
 3     int hash = key.hashCode();
 4     int index = (hash & 0x7FFFFFFF) % tab.length;
 5     // 找到“key對應的Entry(鏈表)”
 6     // 然后在鏈表中找出要刪除的節點,並刪除該節點。
 7     for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
 8         if ((e.hash == hash) && e.key.equals(key)) {
 9             modCount++;
10             if (prev != null) {
11                 prev.next = e.next;
12             } else {
13                 tab[index] = e.next;
14             }
15             count--;
16             V oldValue = e.value;
17             e.value = null;
18             return oldValue;
19         }
20     }
21     return null;
22 }
View Code

 

第3.4部分 Hashtable實現的Cloneable接口

Hashtable實現了Cloneable接口,即實現了clone()方法。
clone()方法的作用很簡單,就是克隆一個Hashtable對象並返回。

 1 // 克隆一個Hashtable,並以Object的形式返回。
 2 public synchronized Object clone() {
 3     try {
 4         Hashtable<K,V> t = (Hashtable<K,V>) super.clone();
 5         t.table = new Entry[table.length];
 6         for (int i = table.length ; i-- > 0 ; ) {
 7             t.table[i] = (table[i] != null)
 8             ? (Entry<K,V>) table[i].clone() : null;
 9         }
10         t.keySet = null;
11         t.entrySet = null;
12         t.values = null;
13         t.modCount = 0;
14         return t;
15     } catch (CloneNotSupportedException e) {
16         // this shouldn't happen, since we are Cloneable
17         throw new InternalError();
18     }
19 }
View Code

 

第3.5部分 Hashtable實現的Serializable接口

Hashtable實現java.io.Serializable,分別實現了串行讀取、寫入功能。

串行寫入函數就是將Hashtable的“總的容量,實際容量,所有的Entry”都寫入到輸出流中
串行讀取函數:根據寫入方式讀出將Hashtable的“總的容量,實際容量,所有的Entry”依次讀出

 1 private synchronized void writeObject(java.io.ObjectOutputStream s)
 2     throws IOException
 3 {
 4     // Write out the length, threshold, loadfactor
 5     s.defaultWriteObject();
 6 
 7     // Write out length, count of elements and then the key/value objects
 8     s.writeInt(table.length);
 9     s.writeInt(count);
10     for (int index = table.length-1; index >= 0; index--) {
11         Entry entry = table[index];
12 
13         while (entry != null) {
14         s.writeObject(entry.key);
15         s.writeObject(entry.value);
16         entry = entry.next;
17         }
18     }
19 }
20 
21 private void readObject(java.io.ObjectInputStream s)
22      throws IOException, ClassNotFoundException
23 {
24     // Read in the length, threshold, and loadfactor
25     s.defaultReadObject();
26 
27     // Read the original length of the array and number of elements
28     int origlength = s.readInt();
29     int elements = s.readInt();
30 
31     // Compute new size with a bit of room 5% to grow but
32     // no larger than the original size.  Make the length
33     // odd if it's large enough, this helps distribute the entries.
34     // Guard against the length ending up zero, that's not valid.
35     int length = (int)(elements * loadFactor) + (elements / 20) + 3;
36     if (length > elements && (length & 1) == 0)
37         length--;
38     if (origlength > 0 && length > origlength)
39         length = origlength;
40 
41     Entry[] table = new Entry[length];
42     count = 0;
43 
44     // Read the number of elements and then all the key/value objects
45     for (; elements > 0; elements--) {
46         K key = (K)s.readObject();
47         V value = (V)s.readObject();
48             // synch could be eliminated for performance
49             reconstitutionPut(table, key, value);
50     }
51     this.table = table;
52 }
View Code

 

第4部分 Hashtable遍歷方式

4.1 遍歷Hashtable的鍵值對

第一步:根據entrySet()獲取Hashtable的“鍵值對”的Set集合。
第二步:通過Iterator迭代器遍歷“第一步”得到的集合。

// 假設table是Hashtable對象
// table中的key是String類型,value是Integer類型
Integer integ = null;
Iterator iter = table.entrySet().iterator();
while(iter.hasNext()) {
    Map.Entry entry = (Map.Entry)iter.next();
    // 獲取key
    key = (String)entry.getKey();
        // 獲取value
    integ = (Integer)entry.getValue();
}

 

4.2 通過Iterator遍歷Hashtable的鍵

第一步:根據keySet()獲取Hashtable的“鍵”的Set集合。
第二步:通過Iterator迭代器遍歷“第一步”得到的集合。

// 假設table是Hashtable對象
// table中的key是String類型,value是Integer類型
String key = null;
Integer integ = null;
Iterator iter = table.keySet().iterator();
while (iter.hasNext()) {
        // 獲取key
    key = (String)iter.next();
        // 根據key,獲取value
    integ = (Integer)table.get(key);
}

 

4.3 通過Iterator遍歷Hashtable的值

第一步:根據value()獲取Hashtable的“值”的集合。
第二步:通過Iterator迭代器遍歷“第一步”得到的集合。

// 假設table是Hashtable對象
// table中的key是String類型,value是Integer類型
Integer value = null;
Collection c = table.values();
Iterator iter= c.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}

 

4.4 通過Enumeration遍歷Hashtable的鍵

第一步:根據keys()獲取Hashtable的集合。
第二步:通過Enumeration遍歷“第一步”得到的集合。

Enumeration enu = table.keys();
while(enu.hasMoreElements()) {
    System.out.println(enu.nextElement());
}   

 

4.5 通過Enumeration遍歷Hashtable的值

第一步:根據elements()獲取Hashtable的集合。
第二步:通過Enumeration遍歷“第一步”得到的集合。

Enumeration enu = table.elements();
while(enu.hasMoreElements()) {
    System.out.println(enu.nextElement());
}

遍歷測試程序如下

  1 import java.util.*;
  2 
  3 /*
  4  * @desc 遍歷Hashtable的測試程序。
  5  *   (01) 通過entrySet()去遍歷key、value,參考實現函數:
  6  *        iteratorHashtableByEntryset()
  7  *   (02) 通過keySet()去遍歷key,參考實現函數:
  8  *        iteratorHashtableByKeyset()
  9  *   (03) 通過values()去遍歷value,參考實現函數:
 10  *        iteratorHashtableJustValues()
 11  *   (04) 通過Enumeration去遍歷key,參考實現函數:
 12  *        enumHashtableKey()
 13  *   (05) 通過Enumeration去遍歷value,參考實現函數:
 14  *        enumHashtableValue()
 15  *
 16  * @author skywang
 17  */
 18 public class HashtableIteratorTest {
 19 
 20     public static void main(String[] args) {
 21         int val = 0;
 22         String key = null;
 23         Integer value = null;
 24         Random r = new Random();
 25         Hashtable table = new Hashtable();
 26 
 27         for (int i=0; i<12; i++) {
 28             // 隨機獲取一個[0,100)之間的數字
 29             val = r.nextInt(100);
 30             
 31             key = String.valueOf(val);
 32             value = r.nextInt(5);
 33             // 添加到Hashtable中
 34             table.put(key, value);
 35             System.out.println(" key:"+key+" value:"+value);
 36         }
 37         // 通過entrySet()遍歷Hashtable的key-value
 38         iteratorHashtableByEntryset(table) ;
 39         
 40         // 通過keySet()遍歷Hashtable的key-value
 41         iteratorHashtableByKeyset(table) ;
 42         
 43         // 單單遍歷Hashtable的value
 44         iteratorHashtableJustValues(table);        
 45 
 46         // 遍歷Hashtable的Enumeration的key
 47         enumHashtableKey(table);
 48 
 49         // 遍歷Hashtable的Enumeration的value
 50         //enumHashtableValue(table);
 51     }
 52             
 53     /*
 54      * 通過Enumeration遍歷Hashtable的key
 55      * 效率高!
 56      */
 57     private static void enumHashtableKey(Hashtable table) {
 58         if (table == null)
 59             return ;
 60 
 61         System.out.println("\nenumeration Hashtable");
 62         Enumeration enu = table.keys();
 63         while(enu.hasMoreElements()) {
 64             System.out.println(enu.nextElement());
 65         }
 66     }
 67 
 68     
 69     /*
 70      * 通過Enumeration遍歷Hashtable的value
 71      * 效率高!
 72      */
 73     private static void enumHashtableValue(Hashtable table) {
 74         if (table == null)
 75             return ;
 76 
 77         System.out.println("\nenumeration Hashtable");
 78         Enumeration enu = table.elements();
 79         while(enu.hasMoreElements()) {
 80             System.out.println(enu.nextElement());
 81         }
 82     }
 83 
 84     /*
 85      * 通過entry set遍歷Hashtable
 86      * 效率高!
 87      */
 88     private static void iteratorHashtableByEntryset(Hashtable table) {
 89         if (table == null)
 90             return ;
 91 
 92         System.out.println("\niterator Hashtable By entryset");
 93         String key = null;
 94         Integer integ = null;
 95         Iterator iter = table.entrySet().iterator();
 96         while(iter.hasNext()) {
 97             Map.Entry entry = (Map.Entry)iter.next();
 98             
 99             key = (String)entry.getKey();
100             integ = (Integer)entry.getValue();
101             System.out.println(key+" -- "+integ.intValue());
102         }
103     }
104 
105     /*
106      * 通過keyset來遍歷Hashtable
107      * 效率低!
108      */
109     private static void iteratorHashtableByKeyset(Hashtable table) {
110         if (table == null)
111             return ;
112 
113         System.out.println("\niterator Hashtable By keyset");
114         String key = null;
115         Integer integ = null;
116         Iterator iter = table.keySet().iterator();
117         while (iter.hasNext()) {
118             key = (String)iter.next();
119             integ = (Integer)table.get(key);
120             System.out.println(key+" -- "+integ.intValue());
121         }
122     }
123     
124 
125     /*
126      * 遍歷Hashtable的values
127      */
128     private static void iteratorHashtableJustValues(Hashtable table) {
129         if (table == null)
130             return ;
131         
132         Collection c = table.values();
133         Iterator iter= c.iterator();
134         while (iter.hasNext()) {
135             System.out.println(iter.next());
136        }
137     }
138 }
View Code

 

第5部分 Hashtable示例

下面通過一個實例來學習如何使用Hashtable。

 1 import java.util.*;
 2 
 3 /*
 4  * @desc Hashtable的測試程序。
 5  *
 6  * @author skywang
 7  */
 8 public class HashtableTest {
 9     public static void main(String[] args) {
10         testHashtableAPIs();
11     }
12 
13     private static void testHashtableAPIs() {
14         // 初始化隨機種子
15         Random r = new Random();
16         // 新建Hashtable
17         Hashtable table = new Hashtable();
18         // 添加操作
19         table.put("one", r.nextInt(10));
20         table.put("two", r.nextInt(10));
21         table.put("three", r.nextInt(10));
22 
23         // 打印出table
24         System.out.println("table:"+table );
25 
26         // 通過Iterator遍歷key-value
27         Iterator iter = table.entrySet().iterator();
28         while(iter.hasNext()) {
29             Map.Entry entry = (Map.Entry)iter.next();
30             System.out.println("next : "+ entry.getKey() +" - "+entry.getValue());
31         }
32 
33         // Hashtable的鍵值對個數        
34         System.out.println("size:"+table.size());
35 
36         // containsKey(Object key) :是否包含鍵key
37         System.out.println("contains key two : "+table.containsKey("two"));
38         System.out.println("contains key five : "+table.containsKey("five"));
39 
40         // containsValue(Object value) :是否包含值value
41         System.out.println("contains value 0 : "+table.containsValue(new Integer(0)));
42 
43         // remove(Object key) : 刪除鍵key對應的鍵值對
44         table.remove("three");
45 
46         System.out.println("table:"+table );
47 
48         // clear() : 清空Hashtable
49         table.clear();
50 
51         // isEmpty() : Hashtable是否為空
52         System.out.println((table.isEmpty()?"table is empty":"table is not empty") );
53     }
54 
55 }
View Code

(某一次)運行結果

table:{two=5, one=0, three=6}
next : two - 5
next : one - 0
next : three - 6
size:3
contains key two : true
contains key five : false
contains value 0 : true
table:{two=5, one=0}
table is empty

 


更多內容

Java 集合系列目錄

Java 集合系列01之 總體框架

Java 集合系列10之 HashMap詳細介紹(源碼解析)和使用示例

Java 集合系列11之 Hashtable詳細介紹(源碼解析)和使用示例

Java 集合系列12之 TreeMap詳細介紹(源碼解析)和使用示例

Java 集合系列13之 WeakHashMap詳細介紹(源碼解析)和使用示例

Java 集合系列14之 Map總結(HashMap, Hashtable, TreeMap, WeakHashMap等使用場景)

Java 集合系列18之 Iterator和Enumeration比較

 


免責聲明!

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



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