您的位置:首页 > 编程语言 > Java开发

深入Java集合学习系列:Hashtable的实现原理

2014-12-27 22:05 537 查看
我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable。

第1部分 Hashtable介绍

第2部分 Hashtable数据结构

第3部分 Hashtable源码解析(基于JDK1.6.0_45)

第4部分 Hashtable遍历方式

第5部分 Hashtable示例

转载请注明出处:/content/3625840.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 }


说明: 在详细介绍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个构造函数



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 }


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


遍历测试程序如下



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 }



第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 }


(某一次)运行结果

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: