一.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的构造函数

  1. // 默认构造函数。
  2. public Hashtable()
  3. // 指定“容量大小”的构造函数
  4. public Hashtable(int initialCapacity)
  5. // 指定“容量大小”和“加载因子”的构造函数
  6. public Hashtable(int initialCapacity, float loadFactor)
  7. // 包含“子Map”的构造函数
  8. public Hashtable(Map<? extends K, ? extends V> t)

Hashtable的API

  1. synchronized void clear()
  2. synchronized Object clone()
  3. boolean contains(Object value)
  4. synchronized boolean containsKey(Object key)
  5. synchronized boolean containsValue(Object value)
  6. synchronized Enumeration<V> elements()
  7. synchronized Set<Entry<K, V>> entrySet()
  8. synchronized boolean equals(Object object)
  9. synchronized V get(Object key)
  10. synchronized int hashCode()
  11. synchronized boolean isEmpty()
  12. synchronized Set<K> keySet()
  13. synchronized Enumeration<K> keys()
  14. synchronized V put(K key, V value)
  15. synchronized void putAll(Map<? extends K, ? extends V> map)
  16. synchronized V remove(Object key)
  17. synchronized int size()
  18. synchronized String toString()
  19. synchronized Collection<V> values()

二.Hashtable数据结构

Hashtable的继承关系

  1. java.lang.Object
  2. java.util.Dictionary<K, V>
  3. java.util.Hashtable<K, V>
  4. public class Hashtable<K,V> extends Dictionary<K,V>
  5. implements Map<K,V>, Cloneable, java.io.Serializable { }

Hashtable与Map关系如下图:

Hashtable详细介绍(源码解析)和使用示例 - 图1

从图中可以看出:
(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机制的

三.Hashtable源码解析(基于JDK1.6.0_45)

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

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

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

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

3.1.1 Hashtable数据存储数组

private transient Entry[] table;

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

3.1.2 数据节点Entry的数据结构

private static class Entry<K,V> implements Map.Entry<K,V> {
    // 哈希值
    int hash;
    K key;
    V value;
    // 指向的下一个Entry,即链表的下一个节点
    Entry<K,V> next;

    // 构造函数
    protected Entry(int hash, K key, V value, Entry<K,V> next) {
        this.hash = hash;
        this.key = key;
        this.value = value;
        this.next = next;
    }

    protected Object clone() {
        return new Entry<K,V>(hash, key, value,
              (next==null ? null : (Entry<K,V>) next.clone()));
    }

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }

    // 设置value。若value是null,则抛出异常。
    public V setValue(V value) {
        if (value == null)
            throw new NullPointerException();

        V oldValue = this.value;
        this.value = value;
        return oldValue;
    }

    // 覆盖equals()方法,判断两个Entry是否相等。
    // 若两个Entry的key和value都相等,则认为它们相等。
    public boolean equals(Object o) {
        if (!(o instanceof Map.Entry))
            return false;
        Map.Entry e = (Map.Entry)o;

        return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
           (value==null ? e.getValue()==null : value.equals(e.getValue()));
    }

    public int hashCode() {
        return hash ^ (value==null ? 0 : value.hashCode());
    }

    public String toString() {
        return key.toString()+"="+value.toString();
    }
}

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

第3.2部分 Hashtable的构造函数

Hashtable共包括4个构造函数

// 默认构造函数。
public Hashtable() {
    // 默认构造函数,指定的容量大小是11;加载因子是0.75
    this(11, 0.75f);
}

// 指定“容量大小”的构造函数
public Hashtable(int initialCapacity) {
    this(initialCapacity, 0.75f);
}

// 指定“容量大小”和“加载因子”的构造函数
public Hashtable(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal Load: "+loadFactor);

    if (initialCapacity==0)
        initialCapacity = 1;
    this.loadFactor = loadFactor;
    table = new Entry[initialCapacity];
    threshold = (int)(initialCapacity * loadFactor);
}

// 包含“子Map”的构造函数
public Hashtable(Map<? extends K, ? extends V> t) {
    this(Math.max(2*t.size(), 11), 0.75f);
    // 将“子Map”的全部元素都添加到Hashtable中
    putAll(t);
}

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

3.3.1 clear()

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

public synchronized void clear() {
    Entry tab[] = table;
    modCount++;
    for (int index = tab.length; --index >= 0; )
        tab[index] = null;
    count = 0;
}

3.3.2 contains()containsValue()

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

public boolean containsValue(Object value) {
    return contains(value);
}

public synchronized boolean contains(Object value) {
    // Hashtable中“键值对”的value不能是null,
    // 若是null的话,抛出异常!
    if (value == null) {
        throw new NullPointerException();
    }

    // 从后向前遍历table数组中的元素(Entry)
    // 对于每个Entry(单向链表),逐个遍历,判断节点的值是否等于value
    Entry tab[] = table;
    for (int i = tab.length ; i-- > 0 ;) {
        for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
            if (e.value.equals(value)) {
                return true;
            }
        }
    }
    return false;
}

3.3.3 containsKey()

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

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

3.3.4 elements()

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

public synchronized Enumeration<V> elements() {
    return this.<V>getEnumeration(VALUES);
}

// 获取Hashtable的枚举类对象
private <T> Enumeration<T> getEnumeration(int type) {
    if (count == 0) {
        return (Enumeration<T>)emptyEnumerator;
    } else {
        return new Enumerator<T>(type, false);
    }
}

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

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

private static Enumeration emptyEnumerator = new EmptyEnumerator();

// 空枚举类
// 当Hashtable的实际大小为0;此时,又要通过Enumeration遍历Hashtable时,返回的是“空枚举类”的对象。
private static class EmptyEnumerator implements Enumeration<Object> {

    EmptyEnumerator() {
    }

    // 空枚举类的hasMoreElements() 始终返回false
    public boolean hasMoreElements() {
        return false;
    }

    // 空枚举类的nextElement() 抛出异常
    public Object nextElement() {
        throw new NoSuchElementException("Hashtable Enumerator");
    }
}

我们在来看看Enumeration类

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

private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
    // 指向Hashtable的table
    Entry[] table = Hashtable.this.table;
    // Hashtable的总的大小
    int index = table.length;
    Entry<K,V> entry = null;
    Entry<K,V> lastReturned = null;
    int type;

    // Enumerator是 “迭代器(Iterator)” 还是 “枚举类(Enumeration)”的标志
    // iterator为true,表示它是迭代器;否则,是枚举类。
    boolean iterator;

    // 在将Enumerator当作迭代器使用时会用到,用来实现fail-fast机制。
    protected int expectedModCount = modCount;

    Enumerator(int type, boolean iterator) {
        this.type = type;
        this.iterator = iterator;
    }

    // 从遍历table的数组的末尾向前查找,直到找到不为null的Entry。
    public boolean hasMoreElements() {
        Entry<K,V> e = entry;
        int i = index;
        Entry[] t = table;
        /* Use locals for faster loop iteration */
        while (e == null && i > 0) {
            e = t[--i];
        }
        entry = e;
        index = i;
        return e != null;
    }

    // 获取下一个元素
    // 注意:从hasMoreElements() 和nextElement() 可以看出“Hashtable的elements()遍历方式”
    // 首先,从后向前的遍历table数组。table数组的每个节点都是一个单向链表(Entry)。
    // 然后,依次向后遍历单向链表Entry。
    public T nextElement() {
        Entry<K,V> et = entry;
        int i = index;
        Entry[] t = table;
        /* Use locals for faster loop iteration */
        while (et == null && i > 0) {
            et = t[--i];
        }
        entry = et;
        index = i;
        if (et != null) {
            Entry<K,V> e = lastReturned = entry;
            entry = e.next;
            return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
        }
        throw new NoSuchElementException("Hashtable Enumerator");
    }

    // 迭代器Iterator的判断是否存在下一个元素
    // 实际上,它是调用的hasMoreElements()
    public boolean hasNext() {
        return hasMoreElements();
    }

    // 迭代器获取下一个元素
    // 实际上,它是调用的nextElement()
    public T next() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        return nextElement();
    }

    // 迭代器的remove()接口。
    // 首先,它在table数组中找出要删除元素所在的Entry,
    // 然后,删除单向链表Entry中的元素。
    public void remove() {
        if (!iterator)
            throw new UnsupportedOperationException();
        if (lastReturned == null)
            throw new IllegalStateException("Hashtable Enumerator");
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();

        synchronized(Hashtable.this) {
            Entry[] tab = Hashtable.this.table;
            int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;

            for (Entry<K,V> e = tab[index], prev = null; e != null;
                 prev = e, e = e.next) {
                if (e == lastReturned) {
                    modCount++;
                    expectedModCount++;
                    if (prev == null)
                        tab[index] = e.next;
                    else
                        prev.next = e.next;
                    count--;
                    lastReturned = null;
                    return;
                }
            }
            throw new ConcurrentModificationException();
        }
    }
}

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

3.3.5 get()

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

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

3.3.6 put()

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

public synchronized V put(K key, V value) {
    // Hashtable中不能插入value为null的元素!!!
    if (value == null) {
        throw new NullPointerException();
    }

    // 若“Hashtable中已存在键为key的键值对”,
    // 则用“新的value”替换“旧的value”
    Entry tab[] = table;
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;
    for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
        if ((e.hash == hash) && e.key.equals(key)) {
            V old = e.value;
            e.value = value;
            return old;
            }
    }

    // 若“Hashtable中不存在键为key的键值对”,
    // (01) 将“修改统计数”+1
    modCount++;
    // (02) 若“Hashtable实际容量” > “阈值”(阈值=总的容量 * 加载因子)
    //  则调整Hashtable的大小
    if (count >= threshold) {
        // Rehash the table if the threshold is exceeded
        rehash();

        tab = table;
        index = (hash & 0x7FFFFFFF) % tab.length;
    }

    // (03) 将“Hashtable中index”位置的Entry(链表)保存到e中
    Entry<K,V> e = tab[index];
    // (04) 创建“新的Entry节点”,并将“新的Entry”插入“Hashtable的index位置”,并设置e为“新的Entry”的下一个元素(即“新Entry”为链表表头)。        
    tab[index] = new Entry<K,V>(hash, key, value, e);
    // (05) 将“Hashtable的实际容量”+1
    count++;
    return null;
}

3.3.7 putAll()

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

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

3.3.8 remove()

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

public synchronized V remove(Object key) {
    Entry tab[] = table;
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;
    // 找到“key对应的Entry(链表)”
    // 然后在链表中找出要删除的节点,并删除该节点。
    for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
        if ((e.hash == hash) && e.key.equals(key)) {
            modCount++;
            if (prev != null) {
                prev.next = e.next;
            } else {
                tab[index] = e.next;
            }
            count--;
            V oldValue = e.value;
            e.value = null;
            return oldValue;
        }
    }
    return null;
}

第3.4部分 Hashtable实现的Cloneable接口

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

// 克隆一个Hashtable,并以Object的形式返回。
public synchronized Object clone() {
    try {
        Hashtable<K,V> t = (Hashtable<K,V>) super.clone();
        t.table = new Entry[table.length];
        for (int i = table.length ; i-- > 0 ; ) {
            t.table[i] = (table[i] != null)
            ? (Entry<K,V>) table[i].clone() : null;
        }
        t.keySet = null;
        t.entrySet = null;
        t.values = null;
        t.modCount = 0;
        return t;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError();
    }
}

第3.5部分 Hashtable实现的Serializable接口

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

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

private synchronized void writeObject(java.io.ObjectOutputStream s)
    throws IOException
{
    // Write out the length, threshold, loadfactor
    s.defaultWriteObject();

    // Write out length, count of elements and then the key/value objects
    s.writeInt(table.length);
    s.writeInt(count);
    for (int index = table.length-1; index >= 0; index--) {
        Entry entry = table[index];

        while (entry != null) {
        s.writeObject(entry.key);
        s.writeObject(entry.value);
        entry = entry.next;
        }
    }
}

private void readObject(java.io.ObjectInputStream s)
     throws IOException, ClassNotFoundException
{
    // Read in the length, threshold, and loadfactor
    s.defaultReadObject();

    // Read the original length of the array and number of elements
    int origlength = s.readInt();
    int elements = s.readInt();

    // Compute new size with a bit of room 5% to grow but
    // no larger than the original size.  Make the length
    // odd if it's large enough, this helps distribute the entries.
    // Guard against the length ending up zero, that's not valid.
    int length = (int)(elements * loadFactor) + (elements / 20) + 3;
    if (length > elements && (length & 1) == 0)
        length--;
    if (origlength > 0 && length > origlength)
        length = origlength;

    Entry[] table = new Entry[length];
    count = 0;

    // Read the number of elements and then all the key/value objects
    for (; elements > 0; elements--) {
        K key = (K)s.readObject();
        V value = (V)s.readObject();
            // synch could be eliminated for performance
            reconstitutionPut(table, key, value);
    }
    this.table = table;
}

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

遍历测试程序如下

import java.util.*;

/*
 * @desc 遍历Hashtable的测试程序。
 *   (01) 通过entrySet()去遍历key、value,参考实现函数:
 *        iteratorHashtableByEntryset()
 *   (02) 通过keySet()去遍历key,参考实现函数:
 *        iteratorHashtableByKeyset()
 *   (03) 通过values()去遍历value,参考实现函数:
 *        iteratorHashtableJustValues()
 *   (04) 通过Enumeration去遍历key,参考实现函数:
 *        enumHashtableKey()
 *   (05) 通过Enumeration去遍历value,参考实现函数:
 *        enumHashtableValue()
 *
 * @author skywang
 */
public class HashtableIteratorTest {

    public static void main(String[] args) {
        int val = 0;
        String key = null;
        Integer value = null;
        Random r = new Random();
        Hashtable table = new Hashtable();

        for (int i=0; i<12; i++) {
            // 随机获取一个[0,100)之间的数字
            val = r.nextInt(100);

            key = String.valueOf(val);
            value = r.nextInt(5);
            // 添加到Hashtable中
            table.put(key, value);
            System.out.println(" key:"+key+" value:"+value);
        }
        // 通过entrySet()遍历Hashtable的key-value
        iteratorHashtableByEntryset(table) ;

        // 通过keySet()遍历Hashtable的key-value
        iteratorHashtableByKeyset(table) ;

        // 单单遍历Hashtable的value
        iteratorHashtableJustValues(table);        

        // 遍历Hashtable的Enumeration的key
        enumHashtableKey(table);

        // 遍历Hashtable的Enumeration的value
        //enumHashtableValue(table);
    }

    /*
     * 通过Enumeration遍历Hashtable的key
     * 效率高!
     */
    private static void enumHashtableKey(Hashtable table) {
        if (table == null)
            return ;

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


    /*
     * 通过Enumeration遍历Hashtable的value
     * 效率高!
     */
    private static void enumHashtableValue(Hashtable table) {
        if (table == null)
            return ;

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

    /*
     * 通过entry set遍历Hashtable
     * 效率高!
     */
    private static void iteratorHashtableByEntryset(Hashtable table) {
        if (table == null)
            return ;

        System.out.println("\niterator Hashtable By entryset");
        String key = null;
        Integer integ = null;
        Iterator iter = table.entrySet().iterator();
        while(iter.hasNext()) {
            Map.Entry entry = (Map.Entry)iter.next();

            key = (String)entry.getKey();
            integ = (Integer)entry.getValue();
            System.out.println(key+" -- "+integ.intValue());
        }
    }

    /*
     * 通过keyset来遍历Hashtable
     * 效率低!
     */
    private static void iteratorHashtableByKeyset(Hashtable table) {
        if (table == null)
            return ;

        System.out.println("\niterator Hashtable By keyset");
        String key = null;
        Integer integ = null;
        Iterator iter = table.keySet().iterator();
        while (iter.hasNext()) {
            key = (String)iter.next();
            integ = (Integer)table.get(key);
            System.out.println(key+" -- "+integ.intValue());
        }
    }


    /*
     * 遍历Hashtable的values
     */
    private static void iteratorHashtableJustValues(Hashtable table) {
        if (table == null)
            return ;

        Collection c = table.values();
        Iterator iter= c.iterator();
        while (iter.hasNext()) {
            System.out.println(iter.next());
       }
    }
}

五.Hashtable示例

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

import java.util.*;

/*
 * @desc Hashtable的测试程序。
 *
 * @author skywang
 */
public class HashtableTest {
    public static void main(String[] args) {
        testHashtableAPIs();
    }

    private static void testHashtableAPIs() {
        // 初始化随机种子
        Random r = new Random();
        // 新建Hashtable
        Hashtable table = new Hashtable();
        // 添加操作
        table.put("one", r.nextInt(10));
        table.put("two", r.nextInt(10));
        table.put("three", r.nextInt(10));

        // 打印出table
        System.out.println("table:"+table );

        // 通过Iterator遍历key-value
        Iterator iter = table.entrySet().iterator();
        while(iter.hasNext()) {
            Map.Entry entry = (Map.Entry)iter.next();
            System.out.println("next : "+ entry.getKey() +" - "+entry.getValue());
        }

        // Hashtable的键值对个数        
        System.out.println("size:"+table.size());

        // containsKey(Object key) :是否包含键key
        System.out.println("contains key two : "+table.containsKey("two"));
        System.out.println("contains key five : "+table.containsKey("five"));

        // containsValue(Object value) :是否包含值value
        System.out.println("contains value 0 : "+table.containsValue(new Integer(0)));

        // remove(Object key) : 删除键key对应的键值对
        table.remove("three");

        System.out.println("table:"+table );

        // clear() : 清空Hashtable
        table.clear();

        // isEmpty() : Hashtable是否为空
        System.out.println((table.isEmpty()?"table is empty":"table is not empty") );
    }

}

(某一次)运行结果

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