菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
401
0

Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

原创
05/13 14:22
阅读数 45195

 

概要

前一章,我们学习了HashMap。这一章,我们对Hashtable进行学习。
我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable。
第1部分 Hashtable介绍
第2部分 Hashtable数据结构
第3部分 Hashtable源码解析(基于JDK1.6.0_45)
第4部分 Hashtable遍历方式
第5部分 Hashtable示例

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3310887.html

 

第1部分 Hashtable介绍

Hashtable 简介

HashMap一样,Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射
Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。

Hashtable 的实例有两个参数影响其性能:初始容量加载因子。容量 是哈希表中桶 的数量,初始容量 就是哈希表创建时的容量。注意,哈希表的状态为 open:在发生“哈希冲突”的情况下,单个桶会存储多个条目,这些条目必须按顺序搜索。加载因子 是对哈希表在其容量自动增加之前可以达到多满的一个尺度。初始容量和加载因子这两个参数只是对该实现的提示。关于何时以及是否调用 rehash 方法的具体细节则依赖于该实现。
通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查找某个条目的时间(在大多数 Hashtable 操作中,包括 get 和 put 操作,都反映了这一点)。

 

Hashtable的构造函数

// 默认构造函数。
public Hashtable() 

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

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

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

 

Hashtable的API

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

 

第2部分 Hashtable数据结构

Hashtable的继承关系

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

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

 

Hashtable与Map关系如下图:

从图中可以看出:
(01) Hashtable继承于Dictionary类,实现了Map接口。Map是"key-value键值对"接口,Dictionary是声明了操作"键值对"函数接口的抽象类。
(02) Hashtable是通过"拉链法"实现的哈希表。它包括几个重要的成员变量:table, count, threshold, loadFactor, modCount
  table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的"key-value键值对"都是存储在Entry数组中的。
  count是Hashtable的大小,它是Hashtable保存的键值对的数量。
  threshold是Hashtable的阈值,用于判断是否需要调整Hashtable的容量。threshold的值="容量*加载因子"。
  loadFactor就是加载因子。
  modCount是用来实现fail-fast机制的

 

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

为了更了解Hashtable的原理,下面对Hashtable源码代码作出分析。
在阅读源码时,建议参考后面的说明来建立对Hashtable的整体认识,这样更容易理解Hashtable。

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

说明在详细介绍Hashtable的代码之前,我们需要了解:和Hashmap一样,Hashtable也是一个散列表,它也是通过“拉链法”解决哈希冲突的。


第3.1部分 Hashtable的“拉链法”相关内容

3.1.1 Hashtable数据存储数组

private transient Entry[] table;

Hashtable中的key-value都是存储在table数组中的

3.1.2 数据节点Entry的数据结构

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

从中,我们可以看出 Entry 实际上就是一个单向链表。这也是为什么我们说Hashtable是通过拉链法解决哈希冲突的。
Entry 实现了Map.Entry 接口,即实现getKey(), getValue(), setValue(V value), equals(Object o), hashCode()这些函数。这些都是基本的读取/修改key、value值的函数。

 

第3.2部分 Hashtable的构造函数

Hashtable共包括4个构造函数

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

 

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

3.3.1 clear()

clear() 的作用是清空Hashtable。它是将Hashtable的table数组的值全部设为null

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

3.3.2 contains()containsValue()

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

 1 public boolean containsValue(Object value) {
 2     return contains(value);
 3 }
 4 
 5 public synchronized boolean contains(Object value) {
 6     // Hashtable中“键值对”的value不能是null,
 7     // 若是null的话,抛出异常!
 8     if (value == null) {
 9         throw new NullPointerException();
10     }
11 
12     // 从后向前遍历table数组中的元素(Entry)
13     // 对于每个Entry(单向链表),逐个遍历,判断节点的值是否等于value
14     Entry tab[] = table;
15     for (int i = tab.length ; i-- > 0 ;) {
16         for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
17             if (e.value.equals(value)) {
18                 return true;
19             }
20         }
21     }
22     return false;
23 }
View Code

3.3.3 containsKey()

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

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

3.3.4 elements()

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

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

从中,我们可以看出:
(01) 若Hashtable的实际大小为0,则返回“空枚举类”对象emptyEnumerator;
(02) 否则,返回正常的Enumerator的对象。(Enumerator实现了迭代器和枚举两个接口)

我们先看看emptyEnumerator对象是如何实现的

 1 private static Enumeration emptyEnumerator = new EmptyEnumerator();
 2 
 3 // 空枚举类
 4 // 当Hashtable的实际大小为0;此时,又要通过Enumeration遍历Hashtable时,返回的是“空枚举类”的对象。
 5 private static class EmptyEnumerator implements Enumeration<Object> {
 6 
 7     EmptyEnumerator() {
 8     }
 9 
10     // 空枚举类的hasMoreElements() 始终返回false
11     public boolean hasMoreElements() {
12         return false;
13     }
14 
15     // 空枚举类的nextElement() 抛出异常
16     public Object nextElement() {
17         throw new NoSuchElementException("Hashtable Enumerator");
18     }
19 }
View Code

我们在来看看Enumeration类

Enumerator的作用是提供了“通过elements()遍历Hashtable的接口” 和 “通过entrySet()遍历Hashtable的接口”。因为,它同时实现了 “Enumerator接口”和“Iterator接口”。

  1 private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
  2     // 指向Hashtable的table
  3     Entry[] table = Hashtable.this.table;
  4     // Hashtable的总的大小
  5     int index = table.length;
  6     Entry<K,V> entry = null;
  7     Entry<K,V> lastReturned = null;
  8     int type;
  9 
 10     // Enumerator是 “迭代器(Iterator)” 还是 “枚举类(Enumeration)”的标志
 11     // iterator为true,表示它是迭代器;否则,是枚举类。
 12     boolean iterator;
 13 
 14     // 在将Enumerator当作迭代器使用时会用到,用来实现fail-fast机制。
 15     protected int expectedModCount = modCount;
 16 
 17     Enumerator(int type, boolean iterator) {
 18         this.type = type;
 19         this.iterator = iterator;
 20     }
 21 
 22     // 从遍历table的数组的末尾向前查找,直到找到不为null的Entry。
 23     public boolean hasMoreElements() {
 24         Entry<K,V> e = entry;
 25         int i = index;
 26         Entry[] t = table;
 27         /* Use locals for faster loop iteration */
 28         while (e == null && i > 0) {
 29             e = t[--i];
 30         }
 31         entry = e;
 32         index = i;
 33         return e != null;
 34     }
 35 
 36     // 获取下一个元素
 37     // 注意:从hasMoreElements() 和nextElement() 可以看出“Hashtable的elements()遍历方式”
 38     // 首先,从后向前的遍历table数组。table数组的每个节点都是一个单向链表(Entry)。
 39     // 然后,依次向后遍历单向链表Entry。
 40     public T nextElement() {
 41         Entry<K,V> et = entry;
 42         int i = index;
 43         Entry[] t = table;
 44         /* Use locals for faster loop iteration */
 45         while (et == null && i > 0) {
 46             et = t[--i];
 47         }
 48         entry = et;
 49         index = i;
 50         if (et != null) {
 51             Entry<K,V> e = lastReturned = entry;
 52             entry = e.next;
 53             return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
 54         }
 55         throw new NoSuchElementException("Hashtable Enumerator");
 56     }
 57 
 58     // 迭代器Iterator的判断是否存在下一个元素
 59     // 实际上,它是调用的hasMoreElements()
 60     public boolean hasNext() {
 61         return hasMoreElements();
 62     }
 63 
 64     // 迭代器获取下一个元素
 65     // 实际上,它是调用的nextElement()
 66     public T next() {
 67         if (modCount != expectedModCount)
 68             throw new ConcurrentModificationException();
 69         return nextElement();
 70     }
 71 
 72     // 迭代器的remove()接口。
 73     // 首先,它在table数组中找出要删除元素所在的Entry,
 74     // 然后,删除单向链表Entry中的元素。
 75     public void remove() {
 76         if (!iterator)
 77             throw new UnsupportedOperationException();
 78         if (lastReturned == null)
 79             throw new IllegalStateException("Hashtable Enumerator");
 80         if (modCount != expectedModCount)
 81             throw new ConcurrentModificationException();
 82 
 83         synchronized(Hashtable.this) {
 84             Entry[] tab = Hashtable.this.table;
 85             int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
 86 
 87             for (Entry<K,V> e = tab[index], prev = null; e != null;
 88                  prev = e, e = e.next) {
 89                 if (e == lastReturned) {
 90                     modCount++;
 91                     expectedModCount++;
 92                     if (prev == null)
 93                         tab[index] = e.next;
 94                     else
 95                         prev.next = e.next;
 96                     count--;
 97                     lastReturned = null;
 98                     return;
 99                 }
100             }
101             throw new ConcurrentModificationException();
102         }
103     }
104 }
View Code

entrySet(), keySet(), keys(), values()的实现方法和elements()差不多,而且源码中已经明确的给出了注释。这里就不再做过多说明了。

3.3.5 get()

get() 的作用就是获取key对应的value,没有的话返回null

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

3.3.6 put()

put() 的作用是对外提供接口,让Hashtable对象可以通过put()将“key-value”添加到Hashtable中。

 1 public synchronized V put(K key, V value) {
 2     // Hashtable中不能插入value为null的元素!!!
 3     if (value == null) {
 4         throw new NullPointerException();
 5     }
 6 
 7     // 若“Hashtable中已存在键为key的键值对”,
 8     // 则用“新的value”替换“旧的value”
 9     Entry tab[] = table;
10     int hash = key.hashCode();
11     int index = (hash & 0x7FFFFFFF) % tab.length;
12     for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
13         if ((e.hash == hash) && e.key.equals(key)) {
14             V old = e.value;
15             e.value = value;
16             return old;
17             }
18     }
19 
20     // 若“Hashtable中不存在键为key的键值对”,
21     // (01) 将“修改统计数”+1
22     modCount++;
23     // (02) 若“Hashtable实际容量” > “阈值”(阈值=总的容量 * 加载因子)
24     //  则调整Hashtable的大小
25     if (count >= threshold) {
26         // Rehash the table if the threshold is exceeded
27         rehash();
28 
29         tab = table;
30         index = (hash & 0x7FFFFFFF) % tab.length;
31     }
32 
33     // (03) 将“Hashtable中index”位置的Entry(链表)保存到e中
34     Entry<K,V> e = tab[index];
35     // (04) 创建“新的Entry节点”,并将“新的Entry”插入“Hashtable的index位置”,并设置e为“新的Entry”的下一个元素(即“新Entry”为链表表头)。        
36     tab[index] = new Entry<K,V>(hash, key, value, e);
37     // (05) 将“Hashtable的实际容量”+1
38     count++;
39     return null;
40 }
View Code

3.3.7 putAll()

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

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

3.3.8 remove()

remove() 的作用就是删除Hashtable中键为key的元素

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

 

第3.4部分 Hashtable实现的Cloneable接口

Hashtable实现了Cloneable接口,即实现了clone()方法。
clone()方法的作用很简单,就是克隆一个Hashtable对象并返回。

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

 

第3.5部分 Hashtable实现的Serializable接口

Hashtable实现java.io.Serializable,分别实现了串行读取、写入功能。

串行写入函数就是将Hashtable的“总的容量,实际容量,所有的Entry”都写入到输出流中
串行读取函数:根据写入方式读出将Hashtable的“总的容量,实际容量,所有的Entry”依次读出

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

 

第4部分 Hashtable遍历方式

4.1 遍历Hashtable的键值对

第一步:根据entrySet()获取Hashtable的“键值对”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

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

 

4.2 通过Iterator遍历Hashtable的键

第一步:根据keySet()获取Hashtable的“键”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设table是Hashtable对象
// table中的key是String类型,value是Integer类型
String key = null;
Integer integ = null;
Iterator iter = table.keySet().iterator();
while (iter.hasNext()) {
        // 获取key
    key = (String)iter.next();
        // 根据key,获取value
    integ = (Integer)table.get(key);
}

 

4.3 通过Iterator遍历Hashtable的值

第一步:根据value()获取Hashtable的“值”的集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

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

 

4.4 通过Enumeration遍历Hashtable的键

第一步:根据keys()获取Hashtable的集合。
第二步:通过Enumeration遍历“第一步”得到的集合。

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

 

4.5 通过Enumeration遍历Hashtable的值

第一步:根据elements()获取Hashtable的集合。
第二步:通过Enumeration遍历“第一步”得到的集合。

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

遍历测试程序如下

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

 

第5部分 Hashtable示例

下面通过一个实例来学习如何使用Hashtable。

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

(某一次)运行结果

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

 


更多内容

Java 集合系列目录

Java 集合系列01之 总体框架

Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例

Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例

Java 集合系列13之 WeakHashMap详细介绍(源码解析)和使用示例

Java 集合系列14之 Map总结(HashMap, Hashtable, TreeMap, WeakHashMap等使用场景)

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

 

发表评论

0/200
401 点赞
0 评论
收藏
为你推荐 换一批