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