1. /*
  2. * @(#)Hashtable.java 1.82 00/02/02
  3. *
  4. * Copyright 1994-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.util;
  11. import java.io.*;
  12. /**
  13. * This class implements a hashtable, which maps keys to values. Any
  14. * non-<code>null</code> object can be used as a key or as a value. <p>
  15. *
  16. * To successfully store and retrieve objects from a hashtable, the
  17. * objects used as keys must implement the <code>hashCode</code>
  18. * method and the <code>equals</code> method. <p>
  19. *
  20. * An instance of <code>Hashtable</code> has two parameters that affect its
  21. * performance: <i>initial capacity</i> and <i>load factor</i>. The
  22. * <i>capacity</i> is the number of <i>buckets</i> in the hash table, and the
  23. * <i>initial capacity</i> is simply the capacity at the time the hash table
  24. * is created. Note that the hash table is <i>open</i>: in the case a "hash
  25. * collision", a single bucket stores multiple entries, which must be searched
  26. * sequentially. The <i>load factor</i> is a measure of how full the hash
  27. * table is allowed to get before its capacity is automatically increased.
  28. * When the number of entries in the hashtable exceeds the product of the load
  29. * factor and the current capacity, the capacity is increased by calling the
  30. * <code>rehash</code> method.<p>
  31. *
  32. * Generally, the default load factor (.75) offers a good tradeoff between
  33. * time and space costs. Higher values decrease the space overhead but
  34. * increase the time cost to look up an entry (which is reflected in most
  35. * <tt>Hashtable</tt> operations, including <tt>get</tt> and <tt>put</tt>).<p>
  36. *
  37. * The initial capacity controls a tradeoff between wasted space and the
  38. * need for <code>rehash</code> operations, which are time-consuming.
  39. * No <code>rehash</code> operations will <i>ever</i> occur if the initial
  40. * capacity is greater than the maximum number of entries the
  41. * <tt>Hashtable</tt> will contain divided by its load factor. However,
  42. * setting the initial capacity too high can waste space.<p>
  43. *
  44. * If many entries are to be made into a <code>Hashtable</code>,
  45. * creating it with a sufficiently large capacity may allow the
  46. * entries to be inserted more efficiently than letting it perform
  47. * automatic rehashing as needed to grow the table. <p>
  48. *
  49. * This example creates a hashtable of numbers. It uses the names of
  50. * the numbers as keys:
  51. * <p><blockquote><pre>
  52. * Hashtable numbers = new Hashtable();
  53. * numbers.put("one", new Integer(1));
  54. * numbers.put("two", new Integer(2));
  55. * numbers.put("three", new Integer(3));
  56. * </pre></blockquote>
  57. * <p>
  58. * To retrieve a number, use the following code:
  59. * <p><blockquote><pre>
  60. * Integer n = (Integer)numbers.get("two");
  61. * if (n != null) {
  62. * System.out.println("two = " + n);
  63. * }
  64. * </pre></blockquote>
  65. * <p>
  66. * As of the Java 2 platform v1.2, this class has been retrofitted to implement Map,
  67. * so that it becomes a part of Java's collection framework. Unlike
  68. * the new collection implementations, Hashtable is synchronized.<p>
  69. *
  70. * The Iterators returned by the iterator and listIterator methods
  71. * of the Collections returned by all of Hashtable's "collection view methods"
  72. * are <em>fail-fast</em>: if the Hashtable is structurally modified
  73. * at any time after the Iterator is created, in any way except through the
  74. * Iterator's own remove or add methods, the Iterator will throw a
  75. * ConcurrentModificationException. Thus, in the face of concurrent
  76. * modification, the Iterator fails quickly and cleanly, rather than risking
  77. * arbitrary, non-deterministic behavior at an undetermined time in the future.
  78. * The Enumerations returned by Hashtable's keys and values methods are
  79. * <em>not</em> fail-fast.
  80. *
  81. * @author Arthur van Hoff
  82. * @author Josh Bloch
  83. * @version 1.82, 02/02/00
  84. * @see Object#equals(java.lang.Object)
  85. * @see Object#hashCode()
  86. * @see Hashtable#rehash()
  87. * @see Collection
  88. * @see Map
  89. * @see HashMap
  90. * @see TreeMap
  91. * @since JDK1.0
  92. */
  93. public class Hashtable extends Dictionary implements Map, Cloneable,
  94. java.io.Serializable {
  95. /**
  96. * The hash table data.
  97. */
  98. private transient Entry table[];
  99. /**
  100. * The total number of entries in the hash table.
  101. */
  102. private transient int count;
  103. /**
  104. * The table is rehashed when its size exceeds this threshold. (The
  105. * value of this field is (int)(capacity * loadFactor).)
  106. *
  107. * @serial
  108. */
  109. private int threshold;
  110. /**
  111. * The load factor for the hashtable.
  112. *
  113. * @serial
  114. */
  115. private float loadFactor;
  116. /**
  117. * The number of times this Hashtable has been structurally modified
  118. * Structural modifications are those that change the number of entries in
  119. * the Hashtable or otherwise modify its internal structure (e.g.,
  120. * rehash). This field is used to make iterators on Collection-views of
  121. * the Hashtable fail-fast. (See ConcurrentModificationException).
  122. */
  123. private transient int modCount = 0;
  124. /** use serialVersionUID from JDK 1.0.2 for interoperability */
  125. private static final long serialVersionUID = 1421746759512286392L;
  126. /**
  127. * Constructs a new, empty hashtable with the specified initial
  128. * capacity and the specified load factor.
  129. *
  130. * @param initialCapacity the initial capacity of the hashtable.
  131. * @param loadFactor the load factor of the hashtable.
  132. * @exception IllegalArgumentException if the initial capacity is less
  133. * than zero, or if the load factor is nonpositive.
  134. */
  135. public Hashtable(int initialCapacity, float loadFactor) {
  136. if (initialCapacity < 0)
  137. throw new IllegalArgumentException("Illegal Capacity: "+
  138. initialCapacity);
  139. if (loadFactor <= 0 || Float.isNaN(loadFactor))
  140. throw new IllegalArgumentException("Illegal Load: "+loadFactor);
  141. if (initialCapacity==0)
  142. initialCapacity = 1;
  143. this.loadFactor = loadFactor;
  144. table = new Entry[initialCapacity];
  145. threshold = (int)(initialCapacity * loadFactor);
  146. }
  147. /**
  148. * Constructs a new, empty hashtable with the specified initial capacity
  149. * and default load factor, which is <tt>0.75</tt>.
  150. *
  151. * @param initialCapacity the initial capacity of the hashtable.
  152. * @exception IllegalArgumentException if the initial capacity is less
  153. * than zero.
  154. */
  155. public Hashtable(int initialCapacity) {
  156. this(initialCapacity, 0.75f);
  157. }
  158. /**
  159. * Constructs a new, empty hashtable with a default capacity and load
  160. * factor, which is <tt>0.75</tt>.
  161. */
  162. public Hashtable() {
  163. this(11, 0.75f);
  164. }
  165. /**
  166. * Constructs a new hashtable with the same mappings as the given
  167. * Map. The hashtable is created with a capacity of twice the number
  168. * of entries in the given Map or 11 (whichever is greater), and a
  169. * default load factor, which is <tt>0.75</tt>.
  170. *
  171. * @param t the map whose mappings are to be placed in this map.
  172. * @since 1.2
  173. */
  174. public Hashtable(Map t) {
  175. this(Math.max(2*t.size(), 11), 0.75f);
  176. putAll(t);
  177. }
  178. /**
  179. * Returns the number of keys in this hashtable.
  180. *
  181. * @return the number of keys in this hashtable.
  182. */
  183. public int size() {
  184. return count;
  185. }
  186. /**
  187. * Tests if this hashtable maps no keys to values.
  188. *
  189. * @return <code>true</code> if this hashtable maps no keys to values;
  190. * <code>false</code> otherwise.
  191. */
  192. public boolean isEmpty() {
  193. return count == 0;
  194. }
  195. /**
  196. * Returns an enumeration of the keys in this hashtable.
  197. *
  198. * @return an enumeration of the keys in this hashtable.
  199. * @see Enumeration
  200. * @see #elements()
  201. * @see #keySet()
  202. * @see Map
  203. */
  204. public synchronized Enumeration keys() {
  205. return getEnumeration(KEYS);
  206. }
  207. /**
  208. * Returns an enumeration of the values in this hashtable.
  209. * Use the Enumeration methods on the returned object to fetch the elements
  210. * sequentially.
  211. *
  212. * @return an enumeration of the values in this hashtable.
  213. * @see java.util.Enumeration
  214. * @see #keys()
  215. * @see #values()
  216. * @see Map
  217. */
  218. public synchronized Enumeration elements() {
  219. return getEnumeration(VALUES);
  220. }
  221. /**
  222. * Tests if some key maps into the specified value in this hashtable.
  223. * This operation is more expensive than the <code>containsKey</code>
  224. * method.<p>
  225. *
  226. * Note that this method is identical in functionality to containsValue,
  227. * (which is part of the Map interface in the collections framework).
  228. *
  229. * @param value a value to search for.
  230. * @return <code>true</code> if and only if some key maps to the
  231. * <code>value</code> argument in this hashtable as
  232. * determined by the <tt>equals</tt> method;
  233. * <code>false</code> otherwise.
  234. * @exception NullPointerException if the value is <code>null</code>.
  235. * @see #containsKey(Object)
  236. * @see #containsValue(Object)
  237. * @see Map
  238. */
  239. public synchronized boolean contains(Object value) {
  240. if (value == null) {
  241. throw new NullPointerException();
  242. }
  243. Entry tab[] = table;
  244. for (int i = tab.length ; i-- > 0 ;) {
  245. for (Entry e = tab[i] ; e != null ; e = e.next) {
  246. if (e.value.equals(value)) {
  247. return true;
  248. }
  249. }
  250. }
  251. return false;
  252. }
  253. /**
  254. * Returns true if this Hashtable maps one or more keys to this value.<p>
  255. *
  256. * Note that this method is identical in functionality to contains
  257. * (which predates the Map interface).
  258. *
  259. * @param value value whose presence in this Hashtable is to be tested.
  260. * @return <tt>true</tt> if this map maps one or more keys to the
  261. * specified value.
  262. * @see Map
  263. * @since 1.2
  264. */
  265. public boolean containsValue(Object value) {
  266. return contains(value);
  267. }
  268. /**
  269. * Tests if the specified object is a key in this hashtable.
  270. *
  271. * @param key possible key.
  272. * @return <code>true</code> if and only if the specified object
  273. * is a key in this hashtable, as determined by the
  274. * <tt>equals</tt> method; <code>false</code> otherwise.
  275. * @see #contains(Object)
  276. */
  277. public synchronized boolean containsKey(Object key) {
  278. Entry tab[] = table;
  279. int hash = key.hashCode();
  280. int index = (hash & 0x7FFFFFFF) % tab.length;
  281. for (Entry e = tab[index] ; e != null ; e = e.next) {
  282. if ((e.hash == hash) && e.key.equals(key)) {
  283. return true;
  284. }
  285. }
  286. return false;
  287. }
  288. /**
  289. * Returns the value to which the specified key is mapped in this hashtable.
  290. *
  291. * @param key a key in the hashtable.
  292. * @return the value to which the key is mapped in this hashtable;
  293. * <code>null</code> if the key is not mapped to any value in
  294. * this hashtable.
  295. * @see #put(Object, Object)
  296. */
  297. public synchronized Object get(Object key) {
  298. Entry tab[] = table;
  299. int hash = key.hashCode();
  300. int index = (hash & 0x7FFFFFFF) % tab.length;
  301. for (Entry e = tab[index] ; e != null ; e = e.next) {
  302. if ((e.hash == hash) && e.key.equals(key)) {
  303. return e.value;
  304. }
  305. }
  306. return null;
  307. }
  308. /**
  309. * Increases the capacity of and internally reorganizes this
  310. * hashtable, in order to accommodate and access its entries more
  311. * efficiently. This method is called automatically when the
  312. * number of keys in the hashtable exceeds this hashtable's capacity
  313. * and load factor.
  314. */
  315. protected void rehash() {
  316. int oldCapacity = table.length;
  317. Entry oldMap[] = table;
  318. int newCapacity = oldCapacity * 2 + 1;
  319. Entry newMap[] = new Entry[newCapacity];
  320. modCount++;
  321. threshold = (int)(newCapacity * loadFactor);
  322. table = newMap;
  323. for (int i = oldCapacity ; i-- > 0 ;) {
  324. for (Entry old = oldMap[i] ; old != null ; ) {
  325. Entry e = old;
  326. old = old.next;
  327. int index = (e.hash & 0x7FFFFFFF) % newCapacity;
  328. e.next = newMap[index];
  329. newMap[index] = e;
  330. }
  331. }
  332. }
  333. /**
  334. * Maps the specified <code>key</code> to the specified
  335. * <code>value</code> in this hashtable. Neither the key nor the
  336. * value can be <code>null</code>. <p>
  337. *
  338. * The value can be retrieved by calling the <code>get</code> method
  339. * with a key that is equal to the original key.
  340. *
  341. * @param key the hashtable key.
  342. * @param value the value.
  343. * @return the previous value of the specified key in this hashtable,
  344. * or <code>null</code> if it did not have one.
  345. * @exception NullPointerException if the key or value is
  346. * <code>null</code>.
  347. * @see Object#equals(Object)
  348. * @see #get(Object)
  349. */
  350. public synchronized Object put(Object key, Object value) {
  351. // Make sure the value is not null
  352. if (value == null) {
  353. throw new NullPointerException();
  354. }
  355. // Makes sure the key is not already in the hashtable.
  356. Entry tab[] = table;
  357. int hash = key.hashCode();
  358. int index = (hash & 0x7FFFFFFF) % tab.length;
  359. for (Entry e = tab[index] ; e != null ; e = e.next) {
  360. if ((e.hash == hash) && e.key.equals(key)) {
  361. Object old = e.value;
  362. e.value = value;
  363. return old;
  364. }
  365. }
  366. modCount++;
  367. if (count >= threshold) {
  368. // Rehash the table if the threshold is exceeded
  369. rehash();
  370. tab = table;
  371. index = (hash & 0x7FFFFFFF) % tab.length;
  372. }
  373. // Creates the new entry.
  374. Entry e = new Entry(hash, key, value, tab[index]);
  375. tab[index] = e;
  376. count++;
  377. return null;
  378. }
  379. /**
  380. * Removes the key (and its corresponding value) from this
  381. * hashtable. This method does nothing if the key is not in the hashtable.
  382. *
  383. * @param key the key that needs to be removed.
  384. * @return the value to which the key had been mapped in this hashtable,
  385. * or <code>null</code> if the key did not have a mapping.
  386. */
  387. public synchronized Object remove(Object key) {
  388. Entry tab[] = table;
  389. int hash = key.hashCode();
  390. int index = (hash & 0x7FFFFFFF) % tab.length;
  391. for (Entry e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
  392. if ((e.hash == hash) && e.key.equals(key)) {
  393. modCount++;
  394. if (prev != null) {
  395. prev.next = e.next;
  396. } else {
  397. tab[index] = e.next;
  398. }
  399. count--;
  400. Object oldValue = e.value;
  401. e.value = null;
  402. return oldValue;
  403. }
  404. }
  405. return null;
  406. }
  407. /**
  408. * Copies all of the mappings from the specified Map to this Hashtable
  409. * These mappings will replace any mappings that this Hashtable had for any
  410. * of the keys currently in the specified Map.
  411. *
  412. * @param t Mappings to be stored in this map.
  413. * @since 1.2
  414. */
  415. public synchronized void putAll(Map t) {
  416. Iterator i = t.entrySet().iterator();
  417. while (i.hasNext()) {
  418. Map.Entry e = (Map.Entry) i.next();
  419. put(e.getKey(), e.getValue());
  420. }
  421. }
  422. /**
  423. * Clears this hashtable so that it contains no keys.
  424. */
  425. public synchronized void clear() {
  426. Entry tab[] = table;
  427. modCount++;
  428. for (int index = tab.length; --index >= 0; )
  429. tab[index] = null;
  430. count = 0;
  431. }
  432. /**
  433. * Creates a shallow copy of this hashtable. All the structure of the
  434. * hashtable itself is copied, but the keys and values are not cloned.
  435. * This is a relatively expensive operation.
  436. *
  437. * @return a clone of the hashtable.
  438. */
  439. public synchronized Object clone() {
  440. try {
  441. Hashtable t = (Hashtable)super.clone();
  442. t.table = new Entry[table.length];
  443. for (int i = table.length ; i-- > 0 ; ) {
  444. t.table[i] = (table[i] != null)
  445. ? (Entry)table[i].clone() : null;
  446. }
  447. t.keySet = null;
  448. t.entrySet = null;
  449. t.values = null;
  450. t.modCount = 0;
  451. return t;
  452. } catch (CloneNotSupportedException e) {
  453. // this shouldn't happen, since we are Cloneable
  454. throw new InternalError();
  455. }
  456. }
  457. /**
  458. * Returns a string representation of this <tt>Hashtable</tt> object
  459. * in the form of a set of entries, enclosed in braces and separated
  460. * by the ASCII characters "<tt>, </tt>" (comma and space). Each
  461. * entry is rendered as the key, an equals sign <tt>=</tt>, and the
  462. * associated element, where the <tt>toString</tt> method is used to
  463. * convert the key and element to strings. <p>Overrides to
  464. * <tt>toString</tt> method of <tt>Object</tt>.
  465. *
  466. * @return a string representation of this hashtable.
  467. */
  468. public synchronized String toString() {
  469. int max = size() - 1;
  470. StringBuffer buf = new StringBuffer();
  471. Iterator it = entrySet().iterator();
  472. buf.append("{");
  473. for (int i = 0; i <= max; i++) {
  474. Map.Entry e = (Map.Entry) (it.next());
  475. buf.append(e.getKey() + "=" + e.getValue());
  476. if (i < max)
  477. buf.append(", ");
  478. }
  479. buf.append("}");
  480. return buf.toString();
  481. }
  482. private Enumeration getEnumeration(int type) {
  483. if (count == 0) {
  484. return emptyEnumerator;
  485. } else {
  486. return new Enumerator(type, false);
  487. }
  488. }
  489. private Iterator getIterator(int type) {
  490. if (count == 0) {
  491. return emptyIterator;
  492. } else {
  493. return new Enumerator(type, true);
  494. }
  495. }
  496. // Views
  497. private transient Set keySet = null;
  498. private transient Set entrySet = null;
  499. private transient Collection values = null;
  500. /**
  501. * Returns a Set view of the keys contained in this Hashtable. The Set
  502. * is backed by the Hashtable, so changes to the Hashtable are reflected
  503. * in the Set, and vice-versa. The Set supports element removal
  504. * (which removes the corresponding entry from the Hashtable), but not
  505. * element addition.
  506. *
  507. * @return a set view of the keys contained in this map.
  508. * @since 1.2
  509. */
  510. public Set keySet() {
  511. if (keySet == null)
  512. keySet = Collections.synchronizedSet(new KeySet(), this);
  513. return keySet;
  514. }
  515. private class KeySet extends AbstractSet {
  516. public Iterator iterator() {
  517. return getIterator(KEYS);
  518. }
  519. public int size() {
  520. return count;
  521. }
  522. public boolean contains(Object o) {
  523. return containsKey(o);
  524. }
  525. public boolean remove(Object o) {
  526. return Hashtable.this.remove(o) != null;
  527. }
  528. public void clear() {
  529. Hashtable.this.clear();
  530. }
  531. }
  532. /**
  533. * Returns a Set view of the entries contained in this Hashtable.
  534. * Each element in this collection is a Map.Entry. The Set is
  535. * backed by the Hashtable, so changes to the Hashtable are reflected in
  536. * the Set, and vice-versa. The Set supports element removal
  537. * (which removes the corresponding entry from the Hashtable),
  538. * but not element addition.
  539. *
  540. * @return a set view of the mappings contained in this map.
  541. * @see Map.Entry
  542. * @since 1.2
  543. */
  544. public Set entrySet() {
  545. if (entrySet==null)
  546. entrySet = Collections.synchronizedSet(new EntrySet(), this);
  547. return entrySet;
  548. }
  549. private class EntrySet extends AbstractSet {
  550. public Iterator iterator() {
  551. return getIterator(ENTRIES);
  552. }
  553. public boolean contains(Object o) {
  554. if (!(o instanceof Map.Entry))
  555. return false;
  556. Map.Entry entry = (Map.Entry)o;
  557. Object key = entry.getKey();
  558. Entry tab[] = table;
  559. int hash = key.hashCode();
  560. int index = (hash & 0x7FFFFFFF) % tab.length;
  561. for (Entry e = tab[index]; e != null; e = e.next)
  562. if (e.hash==hash && e.equals(entry))
  563. return true;
  564. return false;
  565. }
  566. public boolean remove(Object o) {
  567. if (!(o instanceof Map.Entry))
  568. return false;
  569. Map.Entry entry = (Map.Entry)o;
  570. Object key = entry.getKey();
  571. Entry tab[] = table;
  572. int hash = key.hashCode();
  573. int index = (hash & 0x7FFFFFFF) % tab.length;
  574. for (Entry e = tab[index], prev = null; e != null;
  575. prev = e, e = e.next) {
  576. if (e.hash==hash && e.equals(entry)) {
  577. modCount++;
  578. if (prev != null)
  579. prev.next = e.next;
  580. else
  581. tab[index] = e.next;
  582. count--;
  583. e.value = null;
  584. return true;
  585. }
  586. }
  587. return false;
  588. }
  589. public int size() {
  590. return count;
  591. }
  592. public void clear() {
  593. Hashtable.this.clear();
  594. }
  595. }
  596. /**
  597. * Returns a Collection view of the values contained in this Hashtable.
  598. * The Collection is backed by the Hashtable, so changes to the Hashtable
  599. * are reflected in the Collection, and vice-versa. The Collection
  600. * supports element removal (which removes the corresponding entry from
  601. * the Hashtable), but not element addition.
  602. *
  603. * @return a collection view of the values contained in this map.
  604. * @since 1.2
  605. */
  606. public Collection values() {
  607. if (values==null)
  608. values = Collections.synchronizedCollection(new ValueCollection(),
  609. this);
  610. return values;
  611. }
  612. private class ValueCollection extends AbstractCollection {
  613. public Iterator iterator() {
  614. return getIterator(VALUES);
  615. }
  616. public int size() {
  617. return count;
  618. }
  619. public boolean contains(Object o) {
  620. return containsValue(o);
  621. }
  622. public void clear() {
  623. Hashtable.this.clear();
  624. }
  625. }
  626. // Comparison and hashing
  627. /**
  628. * Compares the specified Object with this Map for equality,
  629. * as per the definition in the Map interface.
  630. *
  631. * @return true if the specified Object is equal to this Map.
  632. * @see Map#equals(Object)
  633. * @since 1.2
  634. */
  635. public synchronized boolean equals(Object o) {
  636. if (o == this)
  637. return true;
  638. if (!(o instanceof Map))
  639. return false;
  640. Map t = (Map) o;
  641. if (t.size() != size())
  642. return false;
  643. Iterator i = entrySet().iterator();
  644. while (i.hasNext()) {
  645. Map.Entry e = (Map.Entry) i.next();
  646. Object key = e.getKey();
  647. Object value = e.getValue();
  648. if (value == null) {
  649. if (!(t.get(key)==null && t.containsKey(key)))
  650. return false;
  651. } else {
  652. if (!value.equals(t.get(key)))
  653. return false;
  654. }
  655. }
  656. return true;
  657. }
  658. /**
  659. * Returns the hash code value for this Map as per the definition in the
  660. * Map interface.
  661. *
  662. * @see Map#hashCode()
  663. * @since 1.2
  664. */
  665. public synchronized int hashCode() {
  666. int h = 0;
  667. Iterator i = entrySet().iterator();
  668. while (i.hasNext())
  669. h += i.next().hashCode();
  670. return h;
  671. }
  672. /**
  673. * Save the state of the Hashtable to a stream (i.e., serialize it).
  674. *
  675. * @serialData The <i>capacity</i> of the Hashtable (the length of the
  676. * bucket array) is emitted (int), followed by the
  677. * <i>size</i> of the Hashtable (the number of key-value
  678. * mappings), followed by the key (Object) and value (Object)
  679. * for each key-value mapping represented by the Hashtable
  680. * The key-value mappings are emitted in no particular order.
  681. */
  682. private synchronized void writeObject(java.io.ObjectOutputStream s)
  683. throws IOException
  684. {
  685. // Write out the length, threshold, loadfactor
  686. s.defaultWriteObject();
  687. // Write out length, count of elements and then the key/value objects
  688. s.writeInt(table.length);
  689. s.writeInt(count);
  690. for (int index = table.length-1; index >= 0; index--) {
  691. Entry entry = table[index];
  692. while (entry != null) {
  693. s.writeObject(entry.key);
  694. s.writeObject(entry.value);
  695. entry = entry.next;
  696. }
  697. }
  698. }
  699. /**
  700. * Reconstitute the Hashtable from a stream (i.e., deserialize it).
  701. */
  702. private synchronized void readObject(java.io.ObjectInputStream s)
  703. throws IOException, ClassNotFoundException
  704. {
  705. // Read in the length, threshold, and loadfactor
  706. s.defaultReadObject();
  707. // Read the original length of the array and number of elements
  708. int origlength = s.readInt();
  709. int elements = s.readInt();
  710. // Compute new size with a bit of room 5% to grow but
  711. // No larger than the original size. Make the length
  712. // odd if it's large enough, this helps distribute the entries.
  713. // Guard against the length ending up zero, that's not valid.
  714. int length = (int)(elements * loadFactor) + (elements / 20) + 3;
  715. if (length > elements && (length & 1) == 0)
  716. length--;
  717. if (origlength > 0 && length > origlength)
  718. length = origlength;
  719. table = new Entry[length];
  720. count = 0;
  721. // Read the number of elements and then all the key/value objects
  722. for (; elements > 0; elements--) {
  723. Object key = s.readObject();
  724. Object value = s.readObject();
  725. put(key, value);
  726. }
  727. }
  728. /**
  729. * Hashtable collision list.
  730. */
  731. private static class Entry implements Map.Entry {
  732. int hash;
  733. Object key;
  734. Object value;
  735. Entry next;
  736. protected Entry(int hash, Object key, Object value, Entry next) {
  737. this.hash = hash;
  738. this.key = key;
  739. this.value = value;
  740. this.next = next;
  741. }
  742. protected Object clone() {
  743. return new Entry(hash, key, value,
  744. (next==null ? null : (Entry)next.clone()));
  745. }
  746. // Map.Entry Ops
  747. public Object getKey() {
  748. return key;
  749. }
  750. public Object getValue() {
  751. return value;
  752. }
  753. public Object setValue(Object value) {
  754. if (value == null)
  755. throw new NullPointerException();
  756. Object oldValue = this.value;
  757. this.value = value;
  758. return oldValue;
  759. }
  760. public boolean equals(Object o) {
  761. if (!(o instanceof Map.Entry))
  762. return false;
  763. Map.Entry e = (Map.Entry)o;
  764. return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
  765. (value==null ? e.getValue()==null : value.equals(e.getValue()));
  766. }
  767. public int hashCode() {
  768. return hash ^ (value==null ? 0 : value.hashCode());
  769. }
  770. public String toString() {
  771. return key.toString()+"="+value.toString();
  772. }
  773. }
  774. // Types of Enumerations/Iterations
  775. private static final int KEYS = 0;
  776. private static final int VALUES = 1;
  777. private static final int ENTRIES = 2;
  778. /**
  779. * A hashtable enumerator class. This class implements both the
  780. * Enumeration and Iterator interfaces, but individual instances
  781. * can be created with the Iterator methods disabled. This is necessary
  782. * to avoid unintentionally increasing the capabilities granted a user
  783. * by passing an Enumeration.
  784. */
  785. private class Enumerator implements Enumeration, Iterator {
  786. Entry[] table = Hashtable.this.table;
  787. int index = table.length;
  788. Entry entry = null;
  789. Entry lastReturned = null;
  790. int type;
  791. /**
  792. * Indicates whether this Enumerator is serving as an Iterator
  793. * or an Enumeration. (true -> Iterator).
  794. */
  795. boolean iterator;
  796. /**
  797. * The modCount value that the iterator believes that the backing
  798. * List should have. If this expectation is violated, the iterator
  799. * has detected concurrent modification.
  800. */
  801. protected int expectedModCount = modCount;
  802. Enumerator(int type, boolean iterator) {
  803. this.type = type;
  804. this.iterator = iterator;
  805. }
  806. public boolean hasMoreElements() {
  807. Entry e = entry;
  808. int i = index;
  809. Entry t[] = table;
  810. /* Use locals for faster loop iteration */
  811. while (e == null && i > 0) {
  812. e = t[--i];
  813. }
  814. entry = e;
  815. index = i;
  816. return e != null;
  817. }
  818. public Object nextElement() {
  819. Entry et = entry;
  820. int i = index;
  821. Entry t[] = table;
  822. /* Use locals for faster loop iteration */
  823. while (et == null && i > 0) {
  824. et = t[--i];
  825. }
  826. entry = et;
  827. index = i;
  828. if (et != null) {
  829. Entry e = lastReturned = entry;
  830. entry = e.next;
  831. return type == KEYS ? e.key : (type == VALUES ? e.value : e);
  832. }
  833. throw new NoSuchElementException("Hashtable Enumerator");
  834. }
  835. // Iterator methods
  836. public boolean hasNext() {
  837. return hasMoreElements();
  838. }
  839. public Object next() {
  840. if (modCount != expectedModCount)
  841. throw new ConcurrentModificationException();
  842. return nextElement();
  843. }
  844. public void remove() {
  845. if (!iterator)
  846. throw new UnsupportedOperationException();
  847. if (lastReturned == null)
  848. throw new IllegalStateException("Hashtable Enumerator");
  849. if (modCount != expectedModCount)
  850. throw new ConcurrentModificationException();
  851. synchronized(Hashtable.this) {
  852. Entry[] tab = Hashtable.this.table;
  853. int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
  854. for (Entry e = tab[index], prev = null; e != null;
  855. prev = e, e = e.next) {
  856. if (e == lastReturned) {
  857. modCount++;
  858. expectedModCount++;
  859. if (prev == null)
  860. tab[index] = e.next;
  861. else
  862. prev.next = e.next;
  863. count--;
  864. lastReturned = null;
  865. return;
  866. }
  867. }
  868. throw new ConcurrentModificationException();
  869. }
  870. }
  871. }
  872. private static EmptyEnumerator emptyEnumerator = new EmptyEnumerator();
  873. private static EmptyIterator emptyIterator = new EmptyIterator();
  874. /**
  875. * A hashtable enumerator class for empty hash tables, specializes
  876. * the general Enumerator
  877. */
  878. private static class EmptyEnumerator implements Enumeration {
  879. EmptyEnumerator() {
  880. }
  881. public boolean hasMoreElements() {
  882. return false;
  883. }
  884. public Object nextElement() {
  885. throw new NoSuchElementException("Hashtable Enumerator");
  886. }
  887. }
  888. /**
  889. * A hashtable iterator class for empty hash tables
  890. */
  891. private static class EmptyIterator implements Iterator {
  892. EmptyIterator() {
  893. }
  894. public boolean hasNext() {
  895. return false;
  896. }
  897. public Object next() {
  898. throw new NoSuchElementException("Hashtable Iterator");
  899. }
  900. public void remove() {
  901. throw new IllegalStateException("Hashtable Iterator");
  902. }
  903. }
  904. }