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