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