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

概要

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

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

 

第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的APIapp

複製代碼
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的繼承關係ide

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是經過"拉鍊法"實現的哈希表。它包括幾個重要的成員變量:tablecountthresholdloadFactormodCount
  table是一個Entry[]數組類型,而Entry實際上就是一個單向鏈表。哈希表的"key-value鍵值對"都是存儲在Entry數組中的。 
  count是Hashtable的大小,它是Hashtable保存的鍵值對的數量。 
  threshold是Hashtable的閾值,用於判斷是否須要調整Hashtable的容量。threshold的值="容量*加載因子"。
  loadFactor就是加載因子。 
  modCount是用來實現fail-fast機制的oop

 

第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 }
複製代碼

說明在詳細介紹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 }
複製代碼

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

 

第3.2部分 Hashtable的構造函數

Hashtable共包括4個構造函數

  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 }
複製代碼

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 }
複製代碼

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 }
複製代碼

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 }
複製代碼

從中,咱們能夠看出:
(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 }
複製代碼

咱們在來看看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 }
複製代碼

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 }
複製代碼

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 }
複製代碼

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 }

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 }
複製代碼

 

第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 }
複製代碼

 

第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 }
複製代碼

 

第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());
}

遍歷測試程序以下

  View Code

 

第5部分 Hashtable示例

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

  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
複製代碼
相關文章
相關標籤/搜索