Hashtable简介

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

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

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

HashTable源码剖析

Hashtable的源码的很多实现都与HashMap差不多,源码如下(加入了比较详细的注释):

  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的源码:

  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. Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

    概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Ha ...

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

    概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Ha ...

  3. java集合树状结构及源码

    java集合树状结构及源码 最近一直想看一下java集合的源码,毕竟平时用的比较多,但总是感觉是跟着习惯new出来一个对象,比如ArrayList,HashMap等等,所以就简单的看了一下,了解了一下 ...

  4. 1.Java集合-HashMap实现原理及源码分析

    哈希表(Hash  Table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常 ...

  5. Java集合详解及List源码分析

    对于数组我们应该很熟悉,一个数组在内存中总是一块连续的存储空间,数组的创建使用new关键字,数组是引用类型的数据,一旦第一个元素的位置确定,那么后面的元素位置也就确定了,数组有一个最大的局限就是数组一 ...

  6. Java 集合系列Stack详细介绍(源码解析)和使用示例

    Stack简介 Stack是栈.它的特性是:先进后出(FILO, First In Last Out). java工具包中的Stack是继承于Vector(矢量队列)的,由于Vector是通过数组实现 ...

  7. Java集合框架之接口Collection源码分析

    本文我们主要学习Java集合框架的根接口Collection,通过本文我们可以进一步了解Collection的属性及提供的方法.在介绍Collection接口之前我们不得不先学习一下Iterable, ...

  8. 【Java集合】试读ArrayList源码

    ArrayList简介 ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAccess, ...

  9. java集合【13】——— Stack源码分析走一波

    前言 集合源码分析系列:Java集合源码分析 前面已经把Vector,ArrayList,LinkedList分析完了,本来是想开始Map这一块,但是看了下面这个接口设计框架图:整个接口框架关系如下( ...

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

    第1部分 Hashtable介绍 和HashMap一样,Hashtable也是一个散列表,它存储的内容是键值对(key-value)映射.Hashtable继承于Dictionary,实现了Map.C ...

随机推荐

  1. grafana 邮件报警

    https://my.oschina.net/go4it/blog/830714 grafana   教程 http://download.csdn.net/detail/shuijinglei198 ...

  2. 第7讲 SPI和RAM IP核

    学习目的: (1) 熟悉SPI接口和它的读写时序: (2) 复习Verilog仿真语句中的$readmemb命令和$display命令: (3) 掌握SPI接口写时序操作的硬件语言描述流程(本例仅以写 ...

  3. Openfire更新服务器名称的方法

    转自:http://blog.csdn.net/vikione/article/details/5996932 Openfire更新服务器名称的方法: 1.登陆openfire管理页面,在主页面下方选 ...

  4. 菜鸟学Java(七)——Ajax+Servlet实现无刷新下拉联动

    下拉联动的功能可以说非常的常用,例如在选择省.市等信息的时候:或者在选择大类.小类的时候.总之,下拉联动很常用.今天就跟大家分享一个简单的二级下拉联动的功能. 大类下拉框:页面加载的时候就初始化大类的 ...

  5. schema中字段类型的定义

    当schema中字段类型为String时,保存的时候如果该字段为Number也可以保存成功,mongoose会自动将其转换为数字字符串. 当schema中字段类型为Number时,保存的时候如果该字段 ...

  6. 探寻main函数的“标准”写法,以及获取main函数的参数、返回值

    main函数表示法        很多同学在初学C或者C++时,都见过各种各样的main函数表示法: main(){/*...*/} void main(){/*...*/} int main(){/ ...

  7. SECURITY ONION:防御领域的kali

    https://securityonion.net/ Security Onion is a free and open source Linux distribution for intrusion ...

  8. java8新特性(六):Stream多线程并行数据处理

    转:http://blog.csdn.net/sunjin9418/article/details/53143588 将一个顺序执行的流转变成一个并发的流只要调用 parallel()方法 publi ...

  9. 【Linux技术】常用的Linux系统调用

    下面一些函数已经过时,被新的更好的函数所代替了(gcc在链接这些函数时会发出警告),但因为兼容的原因还保留着,这些函数将在前面标上“*”号以示区别. 一.进程控制 fork 创建一个新进程 clone ...

  10. ffmpeg抓屏输出的设置

    之前做windows下抓屏输出时使用ffmpeg.exe作为抓屏输出测试,命令行如下: ffmpeg -f gdigrab -i "desktop" -r 25 -vcodec m ...