Hashtable简单介绍

Hashtable相同是基于哈希表实现的,相同每一个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时。相同会自己主动增长。

Hashtable也是JDK1.0引入的类,是线程安全的,能用于多线程环境中。

Hashtable相同实现了Serializable接口,它支持序列化,实现了Cloneable接口。能被克隆。

HashTable源代码剖析

Hashtable的源代码的非常多实现都与HashMap差点儿相同。源代码例如以下(增加了比較具体的凝视):

[java] view
plain
copy

  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. // 保存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被改变的次数,用于fail-fast机制的实现
  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. //计算hash值,直接用key的hashCode取代
  87. int hash = key.hashCode();
  88. // 计算在数组中的索引值
  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. protected void rehash() {
  114. int oldCapacity = table.length;
  115. Entry[] oldMap = table;
  116. //创建新容量大小的Entry数组
  117. int newCapacity = oldCapacity * 2 + 1;
  118. Entry[] newMap = new Entry[newCapacity];
  119. modCount++;
  120. threshold = (int)(newCapacity * loadFactor);
  121. table = newMap;
  122. //将“旧的Hashtable”中的元素拷贝到“新的Hashtable”中
  123. for (int i = oldCapacity ; i-- > 0 ;) {
  124. for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
  125. Entry<K,V> e = old;
  126. old = old.next;
  127. //又一次计算index
  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. // 将“改动统计数”+1
  154. modCount++;
  155. //  若“Hashtable实际容量” > “阈值”(阈值=总的容量 * 载入因子)
  156. //  则调整Hashtable的大小
  157. if (count >= threshold) {
  158. rehash();
  159. tab = table;
  160. index = (hash & 0x7FFFFFFF) % tab.length;
  161. }
  162. //将新的key-value对插入到tab[index]处(即链表的头结点)
  163. Entry<K,V> e = tab[index];
  164. tab[index] = new Entry<K,V>(hash, key, value, e);
  165. count++;
  166. return null;
  167. }
  168. // 删除Hashtable中键为key的元素
  169. public synchronized V remove(Object key) {
  170. Entry tab[] = table;
  171. int hash = key.hashCode();
  172. int index = (hash & 0x7FFFFFFF) % tab.length;
  173. //从table[index]链表中找出要删除的节点。并删除该节点。

  174. //由于是单链表。因此要保留带删节点的前一个节点,才干有效地删除节点
  175. for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
  176. if ((e.hash == hash) && e.key.equals(key)) {
  177. modCount++;
  178. if (prev != null) {
  179. prev.next = e.next;
  180. } else {
  181. tab[index] = e.next;
  182. }
  183. count--;
  184. V oldValue = e.value;
  185. e.value = null;
  186. return oldValue;
  187. }
  188. }
  189. return null;
  190. }
  191. // 将“Map(t)”的中所有元素逐一加入到Hashtable中
  192. public synchronized void putAll(Map<?

    extends K, ? extends V> t) {

  193. for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
  194. put(e.getKey(), e.getValue());
  195. }
  196. // 清空Hashtable
  197. // 将Hashtable的table数组的值所有设为null
  198. public synchronized void clear() {
  199. Entry tab[] = table;
  200. modCount++;
  201. for (int index = tab.length; --index >= 0; )
  202. tab[index] = null;
  203. count = 0;
  204. }
  205. // 克隆一个Hashtable,并以Object的形式返回。
  206. public synchronized Object clone() {
  207. try {
  208. Hashtable<K,V> t = (Hashtable<K,V>) super.clone();
  209. t.table = new Entry[table.length];
  210. for (int i = table.length ; i-- > 0 ; ) {
  211. t.table[i] = (table[i] != null)
  212. ? (Entry<K,V>) table[i].clone() : null;
  213. }
  214. t.keySet = null;
  215. t.entrySet = null;
  216. t.values = null;
  217. t.modCount = 0;
  218. return t;
  219. } catch (CloneNotSupportedException e) {
  220. throw new InternalError();
  221. }
  222. }
  223. public synchronized String toString() {
  224. int max = size() - 1;
  225. if (max == -1)
  226. return "{}";
  227. StringBuilder sb = new StringBuilder();
  228. Iterator<Map.Entry<K,V>> it = entrySet().iterator();
  229. sb.append('{');
  230. for (int i = 0; ; i++) {
  231. Map.Entry<K,V> e = it.next();
  232. K key = e.getKey();
  233. V value = e.getValue();
  234. sb.append(key   == this ? "(this Map)" : key.toString());
  235. sb.append('=');
  236. sb.append(value == this ? "(this Map)" : value.toString());
  237. if (i == max)
  238. return sb.append('}').toString();
  239. sb.append(", ");
  240. }
  241. }
  242. // 获取Hashtable的枚举类对象
  243. // 若Hashtable的实际大小为0,则返回“空枚举类”对象;
  244. // 否则,返回正常的Enumerator的对象。
  245. private <T> Enumeration<T> getEnumeration(int type) {
  246. if (count == 0) {
  247. return (Enumeration<T>)emptyEnumerator;
  248. } else {
  249. return new Enumerator<T>(type, false);
  250. }
  251. }
  252. // 获取Hashtable的迭代器
  253. // 若Hashtable的实际大小为0,则返回“空迭代器”对象。
  254. // 否则,返回正常的Enumerator的对象。(Enumerator实现了迭代器和枚举两个接口)
  255. private <T> Iterator<T> getIterator(int type) {
  256. if (count == 0) {
  257. return (Iterator<T>) emptyIterator;
  258. } else {
  259. return new Enumerator<T>(type, true);
  260. }
  261. }
  262. // Hashtable的“key的集合”。它是一个Set,没有反复元素
  263. private transient volatile Set<K> keySet = null;
  264. // Hashtable的“key-value的集合”。它是一个Set。没有反复元素
  265. private transient volatile Set<Map.Entry<K,V>> entrySet = null;
  266. // Hashtable的“key-value的集合”。它是一个Collection,能够有反复元素
  267. private transient volatile Collection<V> values = null;
  268. // 返回一个被synchronizedSet封装后的KeySet对象
  269. // synchronizedSet封装的目的是对KeySet的全部方法都加入synchronized,实现多线程同步
  270. public Set<K> keySet() {
  271. if (keySet == null)
  272. keySet = Collections.synchronizedSet(new KeySet(), this);
  273. return keySet;
  274. }
  275. // Hashtable的Key的Set集合。

  276. // KeySet继承于AbstractSet,所以,KeySet中的元素没有反复的。
  277. private class KeySet extends AbstractSet<K> {
  278. public Iterator<K> iterator() {
  279. return getIterator(KEYS);
  280. }
  281. public int size() {
  282. return count;
  283. }
  284. public boolean contains(Object o) {
  285. return containsKey(o);
  286. }
  287. public boolean remove(Object o) {
  288. return Hashtable.this.remove(o) != null;
  289. }
  290. public void clear() {
  291. Hashtable.this.clear();
  292. }
  293. }
  294. // 返回一个被synchronizedSet封装后的EntrySet对象
  295. // synchronizedSet封装的目的是对EntrySet的全部方法都加入synchronized,实现多线程同步
  296. public Set<Map.Entry<K,V>> entrySet() {
  297. if (entrySet==null)
  298. entrySet = Collections.synchronizedSet(new EntrySet(), this);
  299. return entrySet;
  300. }
  301. // Hashtable的Entry的Set集合。
  302. // EntrySet继承于AbstractSet。所以。EntrySet中的元素没有反复的。
  303. private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
  304. public Iterator<Map.Entry<K,V>> iterator() {
  305. return getIterator(ENTRIES);
  306. }
  307. public boolean add(Map.Entry<K,V> o) {
  308. return super.add(o);
  309. }
  310. // 查找EntrySet中是否包括Object(0)
  311. // 首先。在table中找到o相应的Entry链表
  312. // 然后,查找Entry链表中是否存在Object
  313. public boolean contains(Object o) {
  314. if (!(o instanceof Map.Entry))
  315. return false;
  316. Map.Entry entry = (Map.Entry)o;
  317. Object key = entry.getKey();
  318. Entry[] tab = table;
  319. int hash = key.hashCode();
  320. int index = (hash & 0x7FFFFFFF) % tab.length;
  321. for (Entry e = tab[index]; e != null; e = e.next)
  322. if (e.hash==hash && e.equals(entry))
  323. return true;
  324. return false;
  325. }
  326. // 删除元素Object(0)
  327. // 首先。在table中找到o相应的Entry链表
  328. // 然后,删除链表中的元素Object
  329. public boolean remove(Object o) {
  330. if (!(o instanceof Map.Entry))
  331. return false;
  332. Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
  333. K key = entry.getKey();
  334. Entry[] tab = table;
  335. int hash = key.hashCode();
  336. int index = (hash & 0x7FFFFFFF) % tab.length;
  337. for (Entry<K,V> e = tab[index], prev = null; e != null;
  338. prev = e, e = e.next) {
  339. if (e.hash==hash && e.equals(entry)) {
  340. modCount++;
  341. if (prev != null)
  342. prev.next = e.next;
  343. else
  344. tab[index] = e.next;
  345. count--;
  346. e.value = null;
  347. return true;
  348. }
  349. }
  350. return false;
  351. }
  352. public int size() {
  353. return count;
  354. }
  355. public void clear() {
  356. Hashtable.this.clear();
  357. }
  358. }
  359. // 返回一个被synchronizedCollection封装后的ValueCollection对象
  360. // synchronizedCollection封装的目的是对ValueCollection的全部方法都加入synchronized,实现多线程同步
  361. public Collection<V> values() {
  362. if (values==null)
  363. values = Collections.synchronizedCollection(new ValueCollection(),
  364. this);
  365. return values;
  366. }
  367. // Hashtable的value的Collection集合。
  368. // ValueCollection继承于AbstractCollection,所以。ValueCollection中的元素能够反复的。
  369. private class ValueCollection extends AbstractCollection<V> {
  370. public Iterator<V> iterator() {
  371. return getIterator(VALUES);
  372. }
  373. public int size() {
  374. return count;
  375. }
  376. public boolean contains(Object o) {
  377. return containsValue(o);
  378. }
  379. public void clear() {
  380. Hashtable.this.clear();
  381. }
  382. }
  383. // 又一次equals()函数
  384. // 若两个Hashtable的全部key-value键值对都相等,则推断它们两个相等
  385. public synchronized boolean equals(Object o) {
  386. if (o == this)
  387. return true;
  388. if (!(o instanceof Map))
  389. return false;
  390. Map<K,V> t = (Map<K,V>) o;
  391. if (t.size() != size())
  392. return false;
  393. try {
  394. // 通过迭代器依次取出当前Hashtable的key-value键值对
  395. // 并推断该键值对,存在于Hashtable中。
  396. // 若不存在,则马上返回false;否则,遍历完“当前Hashtable”并返回true。
  397. Iterator<Map.Entry<K,V>> i = entrySet().iterator();
  398. while (i.hasNext()) {
  399. Map.Entry<K,V> e = i.next();
  400. K key = e.getKey();
  401. V value = e.getValue();
  402. if (value == null) {
  403. if (!(t.get(key)==null && t.containsKey(key)))
  404. return false;
  405. } else {
  406. if (!value.equals(t.get(key)))
  407. return false;
  408. }
  409. }
  410. } catch (ClassCastException unused)   {
  411. return false;
  412. } catch (NullPointerException unused) {
  413. return false;
  414. }
  415. return true;
  416. }
  417. // 计算Entry的hashCode
  418. // 若 Hashtable的实际大小为0 或者 载入因子<0,则返回0。
  419. // 否则,返回“Hashtable中的每一个Entry的key和value的异或值 的总和”。

  420. public synchronized int hashCode() {
  421. int h = 0;
  422. if (count == 0 || loadFactor < 0)
  423. return h;  // Returns zero
  424. loadFactor = -loadFactor;  // Mark hashCode computation in progress
  425. Entry[] tab = table;
  426. for (int i = 0; i < tab.length; i++)
  427. for (Entry e = tab[i]; e != null; e = e.next)
  428. h += e.key.hashCode() ^ e.value.hashCode();
  429. loadFactor = -loadFactor;  // Mark hashCode computation complete
  430. return h;
  431. }
  432. // java.io.Serializable的写入函数
  433. // 将Hashtable的“总的容量。实际容量,全部的Entry”都写入到输出流中
  434. private synchronized void writeObject(java.io.ObjectOutputStream s)
  435. throws IOException
  436. {
  437. // Write out the length, threshold, loadfactor
  438. s.defaultWriteObject();
  439. // Write out length, count of elements and then the key/value objects
  440. s.writeInt(table.length);
  441. s.writeInt(count);
  442. for (int index = table.length-1; index >= 0; index--) {
  443. Entry entry = table[index];
  444. while (entry != null) {
  445. s.writeObject(entry.key);
  446. s.writeObject(entry.value);
  447. entry = entry.next;
  448. }
  449. }
  450. }
  451. // java.io.Serializable的读取函数:依据写入方式读出
  452. // 将Hashtable的“总的容量,实际容量,全部的Entry”依次读出
  453. private void readObject(java.io.ObjectInputStream s)
  454. throws IOException, ClassNotFoundException
  455. {
  456. // Read in the length, threshold, and loadfactor
  457. s.defaultReadObject();
  458. // Read the original length of the array and number of elements
  459. int origlength = s.readInt();
  460. int elements = s.readInt();
  461. // Compute new size with a bit of room 5% to grow but
  462. // no larger than the original size.  Make the length
  463. // odd if it's large enough, this helps distribute the entries.
  464. // Guard against the length ending up zero, that's not valid.
  465. int length = (int)(elements * loadFactor) + (elements / 20) + 3;
  466. if (length > elements && (length & 1) == 0)
  467. length--;
  468. if (origlength > 0 && length > origlength)
  469. length = origlength;
  470. Entry[] table = new Entry[length];
  471. count = 0;
  472. // Read the number of elements and then all the key/value objects
  473. for (; elements > 0; elements--) {
  474. K key = (K)s.readObject();
  475. V value = (V)s.readObject();
  476. // synch could be eliminated for performance
  477. reconstitutionPut(table, key, value);
  478. }
  479. this.table = table;
  480. }
  481. private void reconstitutionPut(Entry[] tab, K key, V value)
  482. throws StreamCorruptedException
  483. {
  484. if (value == null) {
  485. throw new java.io.StreamCorruptedException();
  486. }
  487. // Makes sure the key is not already in the hashtable.
  488. // This should not happen in deserialized version.
  489. int hash = key.hashCode();
  490. int index = (hash & 0x7FFFFFFF) % tab.length;
  491. for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
  492. if ((e.hash == hash) && e.key.equals(key)) {
  493. throw new java.io.StreamCorruptedException();
  494. }
  495. }
  496. // Creates the new entry.
  497. Entry<K,V> e = tab[index];
  498. tab[index] = new Entry<K,V>(hash, key, value, e);
  499. count++;
  500. }
  501. // Hashtable的Entry节点,它本质上是一个单向链表。
  502. // 也因此,我们才干判断出Hashtable是由拉链法实现的散列表
  503. private static class Entry<K,V> implements Map.Entry<K,V> {
  504. // 哈希值
  505. int hash;
  506. K key;
  507. V value;
  508. // 指向的下一个Entry,即链表的下一个节点
  509. Entry<K,V> next;
  510. // 构造函数
  511. protected Entry(int hash, K key, V value, Entry<K,V> next) {
  512. this.hash = hash;
  513. this.key = key;
  514. this.value = value;
  515. this.next = next;
  516. }
  517. protected Object clone() {
  518. return new Entry<K,V>(hash, key, value,
  519. (next==null ? null : (Entry<K,V>) next.clone()));
  520. }
  521. public K getKey() {
  522. return key;
  523. }
  524. public V getValue() {
  525. return value;
  526. }
  527. // 设置value。若value是null,则抛出异常。
  528. public V setValue(V value) {
  529. if (value == null)
  530. throw new NullPointerException();
  531. V oldValue = this.value;
  532. this.value = value;
  533. return oldValue;
  534. }
  535. // 覆盖equals()方法,推断两个Entry是否相等。
  536. // 若两个Entry的key和value都相等,则觉得它们相等。
  537. public boolean equals(Object o) {
  538. if (!(o instanceof Map.Entry))
  539. return false;
  540. Map.Entry e = (Map.Entry)o;
  541. return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
  542. (value==null ? e.getValue()==null : value.equals(e.getValue()));
  543. }
  544. public int hashCode() {
  545. return hash ^ (value==null ?

    0 : value.hashCode());

  546. }
  547. public String toString() {
  548. return key.toString()+"="+value.toString();
  549. }
  550. }
  551. private static final int KEYS = 0;
  552. private static final int VALUES = 1;
  553. private static final int ENTRIES = 2;
  554. // Enumerator的作用是提供了“通过elements()遍历Hashtable的接口” 和 “通过entrySet()遍历Hashtable的接口”。
  555. private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
  556. // 指向Hashtable的table
  557. Entry[] table = Hashtable.this.table;
  558. // Hashtable的总的大小
  559. int index = table.length;
  560. Entry<K,V> entry = null;
  561. Entry<K,V> lastReturned = null;
  562. int type;
  563. // Enumerator是 “迭代器(Iterator)” 还是 “枚举类(Enumeration)”的标志
  564. // iterator为true,表示它是迭代器;否则,是枚举类。
  565. boolean iterator;
  566. // 在将Enumerator当作迭代器使用时会用到,用来实现fail-fast机制。
  567. protected int expectedModCount = modCount;
  568. Enumerator(int type, boolean iterator) {
  569. this.type = type;
  570. this.iterator = iterator;
  571. }
  572. // 从遍历table的数组的末尾向前查找,直到找到不为null的Entry。
  573. public boolean hasMoreElements() {
  574. Entry<K,V> e = entry;
  575. int i = index;
  576. Entry[] t = table;
  577. /* Use locals for faster loop iteration */
  578. while (e == null && i > 0) {
  579. e = t[--i];
  580. }
  581. entry = e;
  582. index = i;
  583. return e != null;
  584. }
  585. // 获取下一个元素
  586. // 注意:从hasMoreElements() 和nextElement() 能够看出“Hashtable的elements()遍历方式”
  587. // 首先,从后向前的遍历table数组。

    table数组的每一个节点都是一个单向链表(Entry)。

  588. // 然后。依次向后遍历单向链表Entry。

  589. public T nextElement() {
  590. Entry<K,V> et = entry;
  591. int i = index;
  592. Entry[] t = table;
  593. /* Use locals for faster loop iteration */
  594. while (et == null && i > 0) {
  595. et = t[--i];
  596. }
  597. entry = et;
  598. index = i;
  599. if (et != null) {
  600. Entry<K,V> e = lastReturned = entry;
  601. entry = e.next;
  602. return type == KEYS ?

    (T)e.key : (type == VALUES ? (T)e.value : (T)e);

  603. }
  604. throw new NoSuchElementException("Hashtable Enumerator");
  605. }
  606. // 迭代器Iterator的推断是否存在下一个元素
  607. // 实际上,它是调用的hasMoreElements()
  608. public boolean hasNext() {
  609. return hasMoreElements();
  610. }
  611. // 迭代器获取下一个元素
  612. // 实际上,它是调用的nextElement()
  613. public T next() {
  614. if (modCount != expectedModCount)
  615. throw new ConcurrentModificationException();
  616. return nextElement();
  617. }
  618. // 迭代器的remove()接口。
  619. // 首先。它在table数组中找出要删除元素所在的Entry,
  620. // 然后,删除单向链表Entry中的元素。
  621. public void remove() {
  622. if (!iterator)
  623. throw new UnsupportedOperationException();
  624. if (lastReturned == null)
  625. throw new IllegalStateException("Hashtable Enumerator");
  626. if (modCount != expectedModCount)
  627. throw new ConcurrentModificationException();
  628. synchronized(Hashtable.this) {
  629. Entry[] tab = Hashtable.this.table;
  630. int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
  631. for (Entry<K,V> e = tab[index], prev = null; e != null;
  632. prev = e, e = e.next) {
  633. if (e == lastReturned) {
  634. modCount++;
  635. expectedModCount++;
  636. if (prev == null)
  637. tab[index] = e.next;
  638. else
  639. prev.next = e.next;
  640. count--;
  641. lastReturned = null;
  642. return;
  643. }
  644. }
  645. throw new ConcurrentModificationException();
  646. }
  647. }
  648. }
  649. private static Enumeration emptyEnumerator = new EmptyEnumerator();
  650. private static Iterator emptyIterator = new EmptyIterator();
  651. // 空枚举类
  652. // 当Hashtable的实际大小为0;此时,又要通过Enumeration遍历Hashtable时,返回的是“空枚举类”的对象。
  653. private static class EmptyEnumerator implements Enumeration<Object> {
  654. EmptyEnumerator() {
  655. }
  656. // 空枚举类的hasMoreElements() 始终返回false
  657. public boolean hasMoreElements() {
  658. return false;
  659. }
  660. // 空枚举类的nextElement() 抛出异常
  661. public Object nextElement() {
  662. throw new NoSuchElementException("Hashtable Enumerator");
  663. }
  664. }
  665. // 空迭代器
  666. // 当Hashtable的实际大小为0。此时,又要通过迭代器遍历Hashtable时,返回的是“空迭代器”的对象。
  667. private static class EmptyIterator implements Iterator<Object> {
  668. EmptyIterator() {
  669. }
  670. public boolean hasNext() {
  671. return false;
  672. }
  673. public Object next() {
  674. throw new NoSuchElementException("Hashtable Iterator");
  675. }
  676. public void remove() {
  677. throw new IllegalStateException("Hashtable Iterator");
  678. }
  679. }
  680. }

几点总结

针对Hashtable。我们相同给出几点比較重要的总结,但要结合与HashMap的比較来总结。

1、二者的存储结构和解决冲突的方法都是同样的。

2、HashTable在不指定容量的情况下的默认容量为11,而HashMap为16,Hashtable不要求底层数组的容量一定要为2的整数次幂,而HashMap则要求一定为2的整数次幂。

3、Hashtable中key和value都不同意为null,而HashMap中key和value都同意为null(key仅仅能有一个为null,而value则能够有多个为null)。

可是假设在Hashtable中有类似put(null,null)的操作。编译相同能够通过。由于key和value都是Object类型,但执行时会抛出NullPointerException异常,这是JDK的规范规定的。我们来看下ContainsKey方法和ContainsValue的源代码:

[java] view
plain
copy

  1. // 推断Hashtable是否包括“值(value)”
  2. public synchronized boolean contains(Object value) {
  3. //注意。Hashtable中的value不能是null。
  4. // 若是null的话,抛出异常!
  5. if (value == null) {
  6. throw new NullPointerException();
  7. }
  8. // 从后向前遍历table数组中的元素(Entry)
  9. // 对于每一个Entry(单向链表),逐个遍历。推断节点的值是否等于value
  10. Entry tab[] = table;
  11. for (int i = tab.length ; i-- > 0 ;) {
  12. for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
  13. if (e.value.equals(value)) {
  14. return true;
  15. }
  16. }
  17. }
  18. return false;
  19. }
  20. public boolean containsValue(Object value) {
  21. return contains(value);
  22. }
  23. // 推断Hashtable是否包括key
  24. public synchronized boolean containsKey(Object key) {
  25. Entry tab[] = table;
  26. /计算hash值,直接用key的hashCode取代
  27. int hash = key.hashCode();
  28. // 计算在数组中的索引值
  29. int index = (hash & 0x7FFFFFFF) % tab.length;
  30. // 找到“key相应的Entry(链表)”,然后在链表中找出“哈希值”和“键值”与key都相等的元素
  31. for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
  32. if ((e.hash == hash) && e.key.equals(key)) {
  33. return true;
  34. }
  35. }
  36. return false;
  37. }

非常明显,假设value为null。会直接抛出NullPointerException异常,但源代码中并没有对key是否为null推断,有点小不解!只是NullPointerException属于RuntimeException异常,是能够由JVM自己主动抛出的,或许对key的值在JVM中有所限制吧。

4、Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。

5、Hashtable计算hash值。直接用key的hashCode(),而HashMap又一次计算了key的hash值,Hashtable在求hash值相应的位置索引时,用取模运算,而HashMap在求位置索引时,则用与运算,且这里一般先用hash&0x7FFFFFFF后。再对length取模,&0x7FFFFFFF的目的是为了将负的hash值转化为正值,由于hash值有可能为负数。而&0x7FFFFFFF后,仅仅有符号外改变,而后面的位都不变。


版权声明:本文博主原创文章。博客,未经同意不得转载。

【Java收集的源代码分析】Hashtable源代码分析的更多相关文章

  1. 通过分析 JDK 源代码研究 TreeMap 红黑树算法实现

    本文转载自http://www.ibm.com/developerworks/cn/java/j-lo-tree/ 目录: TreeSet 和 TreeMap 的关系 TreeMap 的添加节点 Tr ...

  2. Memcached源代码分析 - Memcached源代码分析之消息回应(3)

    文章列表: <Memcached源代码分析 - Memcached源代码分析之基于Libevent的网络模型(1)> <Memcached源代码分析 - Memcached源代码分析 ...

  3. 分析setting源代码获取sd卡大小

    分析setting源代码获取sd卡大小 android系统有一个特点,即开源,我们可以得到任何一个应用的源代码,比如我们不知道这样的android代码怎么写,我们可以打开模拟器里面的设置(settin ...

  4. x264源代码简单分析:宏块分析(Analysis)部分-帧间宏块(Inter)

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  5. x264源代码简单分析:宏块分析(Analysis)部分-帧内宏块(Intra)

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  6. 【Java集合源代码剖析】Hashtable源代码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/36191279 Hashtable简单介绍 Hashtable相同是基于哈希表实现的,相同每 ...

  7. 常用 Java 静态代码分析工具的分析与比较

    常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...

  8. [转载] 常用 Java 静态代码分析工具的分析与比较

    转载自http://www.oschina.net/question/129540_23043 简介: 本文首先介绍了静态代码分析的基本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代 ...

  9. 【转载】常用 Java 静态代码分析工具的分析与比较

    摘自:http://www.oschina.net/question/129540_23043常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基本概念及主要技术,随后 ...

随机推荐

  1. poj 1198 hdu 1401 搜索+剪枝 Solitaire

    写到一半才发现能够用双向搜索4层来写,但已经不愿意改了,干脆暴搜+剪枝水过去算了. 想到一个非常水的剪枝,h函数为  当前点到终点4个点的最短距离加起来除以2.由于最多一步走2格,然后在HDU上T了, ...

  2. tera term 残ALT债券

    Setup -> Keyboard对话框 Meta key变: left 版权声明:本文博客原创文章,博客,未经同意,不得转载.

  3. Java 实现二分(折半)插入排序

    设有一个序列a[0],a[1]...a[n];当中a[i-1]前是已经有序的,当插入时a[i]时,利用二分法搜索a[i]插入的位置 效率:O(N^2),对于初始基本有序的序列,效率上不如直接插入排序: ...

  4. ok6410 u-boot-2012.04.01移植七完善u-boot移植(u-boot移植结束)

    继ok6410 u-boot-2012.04.01移植六后,开发板已支持MLC NAND.DM9000等.但还需要完善比如环境变量.mtdpart分区.裁剪.制作补丁等.下面的工作就是完善移植的u-b ...

  5. vim netrw

    我们现在试一下vim文件功能,当你使用vim尝试打开目录时,vim会自动调用netrw.vim插件打开该目录(从操作系统的视角来看,目录其实是一种特殊的文件).例如,我们在vim中执行命令”:e -/ ...

  6. 怎样从Hadoop安全模式中进入正常模式

    问题: 在Hadoop中,新建一个文件夹,报错了,提示mkdir: org.apache.hadoop.hdfs.server.namenode.SafeModeException: Cannot c ...

  7. ActiveMQ相关背景(转)

    概述 介绍中间件.MOM.JMS.ActiveMQ,及相互的关系. 中间件 由于业务的不同.技术的发展.硬件和软件的选择有所差别,导致了异构组件或应用并存的局面.要使这些异构的组件协同工作,一个有效的 ...

  8. 使用javascript开发2048

    嗯,团队队友开发了一个简单的2048...哈哈,没办法,这游戏那么疯狂,必须搞搞啦,大家能够直接粘贴代码到一个html文件,直接执行就可以 依赖文件:jquery,假设乜有,大家能够自己下载一份 &l ...

  9. Callable 获取线程返回值

    allable与 Future 两功能是Java在兴许版本号中为了适应多并法才增加的,Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它 ...

  10. RTF 格式 说明

    摘要: 本文对RTF文件格式进行分析研究,对RTF文件结构及特性进行了阐述,并分别列举了几个有用性的样例进行具体分析, 终于通过VB程序代码实现了一个RTF书写器(不具有所见即所得特性).本文对软件开 ...