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