ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/Hashtable.java
Revision: 1.2
Committed: Thu May 29 14:20:41 2003 UTC (20 years, 11 months ago) by dl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +0 -0 lines
State: FILE REMOVED
Log Message:
Removed old Hashtable since now moved to j.u.c

File Contents

# Content
1 /*
2 * @(#)Hashtable.java 1.83 00/12/13
3 *
4 * Copyright 1994-2002 Sun Microsystems, Inc. All Rights Reserved.
5 *
6 * This software is the proprietary information of Sun Microsystems, Inc.
7 * Use is subject to license terms.
8 *
9 */
10
11 package java.util;
12 import java.io.*;
13
14 /**
15 * This class implements a hashtable, which maps keys to values. Any
16 * non-<code>null</code> object can be used as a key or as a value. <p>
17 *
18 * To successfully store and retrieve objects from a hashtable, the
19 * objects used as keys must implement the <code>hashCode</code>
20 * method and the <code>equals</code> method. <p>
21 *
22 * An instance of <code>Hashtable</code> has two parameters that
23 * affect its performance: <i>initial capacity</i> and <i>load
24 * factor</i>. The <i>capacity</i> is the number of <i>buckets</i> in
25 * the hash table, and the <i>initial capacity</i> is simply the
26 * capacity at the time the hash table is created. Note that the hash
27 * table is <i>open</i>: in the case a "hash collision", a single
28 * bucket stores multiple entries, which must be searched
29 * sequentially. The <i>load factor</i> is a measure of how full the
30 * hash table is allowed to get before its capacity is automatically
31 * increased. When the number of entries in the hashtable exceeds the
32 * product of the load factor and the current capacity, the capacity
33 * is increased by calling the <code>rehash</code> method.<p>
34 *
35 * Generally, the default load factor (.75) offers a good tradeoff
36 * between time and space costs. Higher values decrease the space
37 * overhead but increase the time cost to look up an entry (which is
38 * reflected in most <tt>Hashtable</tt> operations, including
39 * <tt>get</tt> and <tt>put</tt>).<p>
40 *
41 * The initial capacity controls a tradeoff between wasted space and
42 * the need for <code>rehash</code> operations, which are
43 * time-consuming. No <code>rehash</code> operations will <i>ever</i>
44 * occur if the initial capacity is greater than the maximum number of
45 * entries the <tt>Hashtable</tt> will contain divided by its load
46 * factor. However, setting the initial capacity too high can waste
47 * space.<p>
48 *
49 * If many entries are to be made into a <code>Hashtable</code>,
50 * creating it with a sufficiently large capacity may allow the
51 * entries to be inserted more efficiently than letting it perform
52 * automatic rehashing as needed to grow the table. <p>
53 *
54 * This example creates a hashtable of numbers. It uses the names of
55 * the numbers as keys:
56 * <p><blockquote><pre>
57 * Hashtable numbers = new Hashtable();
58 * numbers.put("one", new Integer(1));
59 * numbers.put("two", new Integer(2));
60 * numbers.put("three", new Integer(3));
61 * </pre></blockquote>
62 * <p>
63 * To retrieve a number, use the following code:
64 * <p><blockquote><pre>
65 * Integer n = (Integer)numbers.get("two");
66 * if (n != null) {
67 * System.out.println("two = " + n);
68 * }
69 * </pre></blockquote>
70 * <p>
71 *
72 * As of the Java 2 platform v1.2, this class has been retrofitted to
73 * implement Map, so that it becomes a part of Java's collection
74 * framework. Unlike the new collection implementations, Hashtable is
75 * fully thread-safe.<p>
76 *
77 * The Iterators returned by the iterator and listIterator methods of
78 * the Collections returned by all of Hashtable's "collection view
79 * methods" are <em>fail-fast</em>: if the Hashtable is structurally
80 * modified at any time after the Iterator is created, in any way
81 * except through the Iterator's own remove or add methods, the
82 * Iterator will throw a ConcurrentModificationException. Thus, in
83 * the face of concurrent modification, the Iterator fails quickly and
84 * cleanly, rather than risking arbitrary, non-deterministic behavior
85 * at an undetermined time in the future. The Enumerations returned
86 * by Hashtable's keys and values methods are <em>not</em> fail-fast.
87 * <p>
88 *
89 * @author Arthur van Hoff
90 * @author Josh Bloch
91 * @author Doug Lea
92 * @version 1.83, 12/13/00
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
103 public class Hashtable extends Dictionary
104 implements Map, Cloneable, Serializable {
105
106 /*
107 * This implementation is thread-safe, but not heavily
108 * synchronized. The basic strategy is to ensure that the hash
109 * table and its lists are ALWAYS kept in a consistent state, so
110 * can be read without locking. Next fields of nodes are
111 * immutable (final). All list additions are performed at the
112 * front of each bin. This makes it easy to check changes, and
113 * also fast to traverse. When nodes would otherwise be changed,
114 * new nodes are created to replace them. This works well for hash
115 * tables since the bin lists tend to be short. (The average
116 * length is less than two for the default load factor threshold.)
117 *
118 * Read operations can thus proceed without locking, but rely on a
119 * memory barrier to ensure that COMPLETED write operations
120 * performed by other threads are noticed. Conveniently, the
121 * "count" field, tracking the number of elements, can also serve
122 * as the volatile variable providing proper read/write
123 * barriers. This is convenient because this field needs to be
124 * read in many read operations anyway. The use of volatiles for
125 * this purpose is only guaranteed to work in accord with normal
126 * expectations in multithreaded environments when run on JVMs
127 * conforming to the clarified JSR133 memory model specification.
128 * This true for hotspot as of release 1.4.
129 *
130 * Implementors note. The basic rules for all this are:
131 * - All unsynchronized read operations must first read
132 * the "count" field, and generally, should not look at table if 0.
133 *
134 * - All synchronized write operations should write to
135 * the "count" field after updating. The operations may not
136 * take any action that could even momentarily cause
137 * a concurrent read operation to see inconsistent
138 * data. This is made easier by the nature of the read
139 * operations in Hashtable. For example, no operation
140 * can reveal that the table has grown but the threshold
141 * has not yet been updated, so there are no atomicity
142 * requirements for this with respect to reads.
143 *
144 * As a guide, all critical volatile reads and writes are marked
145 * in the code as comments.
146 */
147
148 /** use serialVersionUID from JDK 1.0.2 for interoperability */
149 private static final long serialVersionUID = 1421746759512286392L;
150
151 /**
152 * The default initial number of table slots for this table (32).
153 * Used when not otherwise specified in constructor.
154 */
155 static int DEFAULT_INITIAL_CAPACITY = 16;
156
157 /**
158 * The maximum capacity, used if a higher value is implicitly
159 * specified by either of the constructors with arguments. MUST
160 * be a power of two <= 1<<30.
161 */
162 static final int MAXIMUM_CAPACITY = 1 << 30;
163
164 /**
165 * The default load factor for this table. Used when not
166 * otherwise specified in constructor.
167 */
168
169 static final float DEFAULT_LOAD_FACTOR = 0.75f;
170
171 /**
172 * The total number of mappings in the hash table.
173 * Also serves as the read-barrier variable.
174 */
175 private transient volatile int count;
176
177 /**
178 * The hash table data.
179 */
180 private transient Entry[] table;
181
182 /**
183 * The load factor for the hash table. This is also used as a
184 * recursion flag in method hashCode. (Sorry for the sleaze but
185 * this maintains 1.1 compatibility.)
186 *
187 * @serial
188 */
189 private float loadFactor;
190
191 /**
192 * The table is rehashed when its size exceeds this threshold.
193 * (The value of this field is always (int)(capacity *
194 * loadFactor).)
195 *
196 * @serial
197 */
198 private int threshold;
199
200 /**
201 * The number of times this map has been structurally modified
202 * Structural modifications are those that change the number of
203 * mappings in the map or otherwise modify its internal structure
204 * (e.g., rehash). This field is used to make iterators on
205 * Collection-views of the map fail-fast. (See
206 * ConcurrentModificationException).
207 */
208 private transient int modCount;
209
210 // internal utilities
211
212 /**
213 * Return a hash code for non-null Object x.
214 */
215 private static int hash(Object x) {
216 int h = x.hashCode();
217 h += ~(h << 9);
218 h ^= (h >>> 14);
219 h += (h << 4);
220 h ^= (h >>> 10);
221 return h;
222 }
223
224 /**
225 * Check for equality of non-null references x and y.
226 **/
227 private static boolean eq(Object x, Object y) {
228 return x == y || x.equals(y);
229 }
230
231 /**
232 * Return index for hash code h.
233 */
234 private static int indexFor(int h, int length) {
235 return h & (length-1);
236 }
237
238 /**
239 * Set table to new Entry array.
240 * Call only while holding lock or in constructor.
241 **/
242 private void setTable(Entry[] newTable) {
243 table = newTable;
244 threshold = (int)(newTable.length * loadFactor);
245 count = count; // write-volatile
246 }
247
248 /**
249 * Constructs a new, empty map with a default initial capacity
250 * and load factor.
251 */
252 public Hashtable() {
253 loadFactor = DEFAULT_LOAD_FACTOR;
254 setTable(new Entry[DEFAULT_INITIAL_CAPACITY]);
255 }
256
257 /**
258 * Constructs a new, empty map with the specified initial
259 * capacity and the specified load factor.
260 *
261 * @param initialCapacity the initial capacity
262 * The actual initial capacity is rounded to the nearest power of two.
263 * @param loadFactor the load factor of the Hashtable
264 * @throws IllegalArgumentException if the initial capacity is less
265 * than zero, or if the load factor is nonpositive.
266 */
267 public Hashtable(int initialCapacity, float loadFactor) {
268 if (initialCapacity < 0)
269 throw new IllegalArgumentException("Illegal initial capacity: " +
270 initialCapacity);
271 if (loadFactor <= 0 || Float.isNaN(loadFactor))
272 throw new IllegalArgumentException("Illegal Load factor: "+
273 loadFactor);
274 this.loadFactor = loadFactor;
275
276 int capacity;
277 if (initialCapacity > MAXIMUM_CAPACITY)
278 capacity = MAXIMUM_CAPACITY;
279 else {
280 capacity = 1;
281 while (capacity < initialCapacity)
282 capacity <<= 1;
283 }
284
285 setTable(new Entry[capacity]);
286 }
287
288 /**
289 * Constructs a new, empty map with the specified initial
290 * capacity and default load factor.
291 *
292 * @param initialCapacity the initial capacity of the
293 * Hashtable.
294 * The actual initial capacity is rounded to the nearest power of two.
295 * @throws IllegalArgumentException if the initial maximum number
296 * of elements is less
297 * than zero.
298 */
299
300 public Hashtable(int initialCapacity) {
301 this(initialCapacity, DEFAULT_LOAD_FACTOR);
302 }
303
304 /**
305 * Constructs a new map with the same mappings as the given map. The
306 * map is created with a default load factor.
307 */
308
309 public Hashtable(Map t) {
310 this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, 16),
311 DEFAULT_LOAD_FACTOR);
312 putAll(t);
313 }
314
315
316 /**
317 * Returns the number of key-value mappings in this map.
318 *
319 * @return the number of key-value mappings in this map.
320 */
321 public int size() {
322 return count; // read-volatile
323 }
324
325 /**
326 * Returns <tt>true</tt> if this map contains no key-value mappings.
327 *
328 * @return <tt>true</tt> if this map contains no key-value mappings.
329 */
330 public boolean isEmpty() {
331 return count == 0; // read-volatile
332 }
333
334 /**
335 * Returns the value to which the specified key is mapped in this table.
336 *
337 * @param key a key in the table.
338 * @return the value to which the key is mapped in this table;
339 * <code>null</code> if the key is not mapped to any value in
340 * this table.
341 * @exception NullPointerException if the key is
342 * <code>null</code>.
343 * @see #put(Object, Object)
344 */
345 public Object get(Object key) {
346 int hash = hash(key); // throws NullPointerException if key null
347
348 if (count != 0) { // read-volatile
349 Entry[] tab = table;
350 int index = indexFor(hash, tab.length);
351 Entry e = tab[index];
352 while (e != null) {
353 if (e.hash == hash && eq(key, e.key))
354 return e.value;
355 e = e.next;
356 }
357 }
358 return null;
359 }
360
361 /**
362 * Tests if the specified object is a key in this table.
363 *
364 * @param key possible key.
365 * @return <code>true</code> if and only if the specified object
366 * is a key in this table, as determined by the
367 * <tt>equals</tt> method; <code>false</code> otherwise.
368 * @exception NullPointerException if the key is
369 * <code>null</code>.
370 * @see #contains(Object)
371 */
372 public boolean containsKey(Object key) {
373 int hash = hash(key); // throws NullPointerException if key null
374
375 if (count != 0) { // read-volatile
376 Entry[] tab = table;
377 int index = indexFor(hash, tab.length);
378 Entry e = tab[index];
379 while (e != null) {
380 if (e.hash == hash && eq(key, e.key))
381 return true;
382 e = e.next;
383 }
384 }
385 return false;
386 }
387
388 /**
389 * Returns <tt>true</tt> if this map maps one or more keys to the
390 * specified value. Note: This method requires a full internal
391 * traversal of the hash table, and so is much slower than
392 * method <tt>containsKey</tt>.
393 *
394 * @param value value whose presence in this map is to be tested.
395 * @return <tt>true</tt> if this map maps one or more keys to the
396 * specified value.
397 * @exception NullPointerException if the value is <code>null</code>.
398 */
399 public boolean containsValue(Object value) {
400 if (value == null)
401 throw new NullPointerException();
402
403 if (count != 0) {
404 Entry tab[] = table;
405 int len = tab.length;
406 for (int i = 0 ; i < len; i++)
407 for (Entry e = tab[i] ; e != null ; e = e.next)
408 if (value.equals(e.value))
409 return true;
410 }
411 return false;
412 }
413
414
415 /**
416 * Tests if some key maps into the specified value in this table.
417 * This operation is more expensive than the <code>containsKey</code>
418 * method.<p>
419 *
420 * Note that this method is identical in functionality to containsValue,
421 * (which is part of the Map interface in the collections framework).
422 *
423 * @param value a value to search for.
424 * @return <code>true</code> if and only if some key maps to the
425 * <code>value</code> argument in this table as
426 * determined by the <tt>equals</tt> method;
427 * <code>false</code> otherwise.
428 * @exception NullPointerException if the value is <code>null</code>.
429 * @see #containsKey(Object)
430 * @see #containsValue(Object)
431 * @see Map
432 */
433 public boolean contains(Object value) {
434 return containsValue(value);
435 }
436
437 /**
438 * Maps the specified <code>key</code> to the specified
439 * <code>value</code> in this table. Neither the key nor the
440 * value can be <code>null</code>. <p>
441 *
442 * The value can be retrieved by calling the <code>get</code> method
443 * with a key that is equal to the original key.
444 *
445 * @param key the table key.
446 * @param value the value.
447 * @return the previous value of the specified key in this table,
448 * or <code>null</code> if it did not have one.
449 * @exception NullPointerException if the key or value is
450 * <code>null</code>.
451 * @see Object#equals(Object)
452 * @see #get(Object)
453 */
454 public synchronized Object put(Object key, Object value) {
455 if (value == null)
456 throw new NullPointerException();
457 int hash = hash(key);
458 Entry[] tab = table;
459 int index = indexFor(hash, tab.length);
460 Entry first = tab[index];
461
462 for (Entry e = first; e != null; e = e.next) {
463 if (e.hash == hash && eq(key, e.key)) {
464 Object oldValue = e.value;
465 e.value = value;
466 count = count; // write-volatile
467 return oldValue;
468 }
469 }
470
471 tab[index] = new Entry(hash, key, value, first);
472 modCount++;
473 if (++count > threshold) // write-volatile
474 rehash();
475 return null;
476 }
477
478 public synchronized Object putIfAbsent(Object key, Object value) {
479 if (value == null)
480 throw new NullPointerException();
481 int hash = hash(key);
482 Entry[] tab = table;
483 int index = indexFor(hash, tab.length);
484 Entry first = tab[index];
485
486 for (Entry e = first; e != null; e = e.next) {
487 if (e.hash == hash && eq(key, e.key)) {
488 Object oldValue = e.value;
489 count = count; // write-volatile
490 return oldValue;
491 }
492 }
493
494 tab[index] = new Entry(hash, key, value, first);
495 modCount++;
496 if (++count > threshold) // write-volatile
497 rehash();
498 return value;
499 }
500
501 /**
502 * Rehashes the contents of this map into a new table
503 * with a larger capacity. This method is called automatically when the
504 * number of keys in this map exceeds the load factor threshold.
505 */
506 private void rehash() {
507 Entry[] oldTable = table;
508 int oldCapacity = oldTable.length;
509 if (oldCapacity < MAXIMUM_CAPACITY) {
510 Entry[] newTable = new Entry[oldCapacity << 1];
511 transfer(oldTable, newTable);
512 setTable(newTable);
513 }
514 }
515
516 /**
517 * Transfer nodes from old table to new table.
518 */
519 private static void transfer(Entry[] oldTable, Entry[] newTable) {
520 /*
521 * Reclassify nodes in each list to new Map. Because we are
522 * using power-of-two expansion, the elements from each bin
523 * must either stay at same index, or move with a power of two
524 * offset. We eliminate unnecessary node creation by catching
525 * cases where old nodes can be reused because their next
526 * fields won't change. Statistically, at the default
527 * threshhold, only about one-sixth of them need cloning when
528 * a table doubles. The nodes they replace will be garbage
529 * collectable as soon as they are no longer referenced by any
530 * reader thread that may be in the midst of traversing table
531 * right now.
532 */
533
534 int oldCapacity = oldTable.length;
535 int mask = newTable.length - 1;
536 for (int i = 0; i < oldCapacity ; i++) {
537 // We need to guarantee that any existing reads of old Map can
538 // proceed. So we cannot yet null out each bin.
539 Entry e = oldTable[i];
540
541 if (e != null) {
542 Entry next = e.next;
543 int idx = e.hash & mask;
544
545 // Single node on list
546 if (next == null)
547 newTable[idx] = e;
548
549 else {
550 // Reuse trailing consecutive sequence at same slot
551 Entry lastRun = e;
552 int lastIdx = idx;
553 for (Entry last = next; last != null; last = last.next) {
554 int k = last.hash & mask;
555 if (k != lastIdx) {
556 lastIdx = k;
557 lastRun = last;
558 }
559 }
560 newTable[lastIdx] = lastRun;
561
562 // Clone all remaining nodes
563 for (Entry p = e; p != lastRun; p = p.next) {
564 int k = p.hash & mask;
565 newTable[k] = new Entry(p.hash, p.key,
566 p.value, newTable[k]);
567 }
568 }
569 }
570 }
571 }
572
573
574 /**
575 * Copies all of the mappings from the specified map to this one.
576 *
577 * These mappings replace any mappings that this map had for any of the
578 * keys currently in the specified Map.
579 *
580 * @param t Mappings to be stored in this map.
581 */
582
583 public void putAll(Map t) {
584 int n = t.size();
585 // Expand enough to hold at least n elements without resizing.
586 if (n >= threshold)
587 resizeToFit(n);
588
589 for (Iterator it = t.entrySet().iterator(); it.hasNext(); ) {
590 Map.Entry e = (Map.Entry) it.next();
591 put(e.getKey(), e.getValue());
592 }
593 }
594
595 /**
596 * Resize by enough to fit n elements.
597 */
598 private synchronized void resizeToFit(int n) {
599 int newSize = (int)(n / loadFactor + 1);
600 if (newSize > MAXIMUM_CAPACITY)
601 newSize = MAXIMUM_CAPACITY;
602
603 Entry[] oldTable = table;
604 int oldCapacity = oldTable.length;
605 int newCapacity = oldCapacity;
606 while (newCapacity < newSize)
607 newCapacity <<= 1;
608
609 if (newCapacity > oldCapacity) {
610 Entry[] newTable = new Entry[newCapacity];
611 if (count != 0)
612 transfer(oldTable, newTable);
613 setTable(newTable);
614 }
615 }
616
617
618 /**
619 * Removes the key (and its corresponding value) from this
620 * table. This method does nothing if the key is not in the table.
621 *
622 * @param key the key that needs to be removed.
623 * @return the value to which the key had been mapped in this table,
624 * or <code>null</code> if the key did not have a mapping.
625 * @exception NullPointerException if the key is
626 * <code>null</code>.
627 */
628 public synchronized Object remove(Object key) {
629 int hash = hash(key);
630 Entry[] tab = table;
631 int index = indexFor(hash, tab.length);
632 Entry first = tab[index];
633
634 Entry e = first;
635 while (true) {
636 if (e == null)
637 return e;
638 if (e.hash == hash && eq(key, e.key))
639 break;
640 e = e.next;
641 }
642
643 // All entries following removed node can stay in list, but
644 // all preceeding ones need to be cloned.
645 Entry newFirst = e.next;
646 for (Entry p = first; p != e; p = p.next)
647 newFirst = new Entry(p.hash, p.key, p.value, newFirst);
648 tab[index] = newFirst;
649
650 modCount++;
651 count--; // write-volatile
652 return e.value;
653 }
654
655
656 /**
657 * Helper method for entrySet.remove
658 */
659 private synchronized boolean findAndRemoveEntry(Object key,
660 Object value) {
661 return key != null && value != null &&
662 value.equals(get(key)) && (remove(key) != null);
663 }
664
665 /**
666 * Removes all mappings from this map.
667 */
668 public synchronized void clear() {
669 modCount++;
670 Entry tab[] = table;
671 int len = tab.length;
672 for (int i = 0; i < len ; i++)
673 tab[i] = null;
674 count = 0; // write-volatile
675 }
676
677
678 /**
679 * Returns a string representation of this <tt>Hashtable</tt> object
680 * in the form of a set of entries, enclosed in braces and separated
681 * by the ASCII characters "<tt>,&nbsp;</tt>" (comma and space). Each
682 * entry is rendered as the key, an equals sign <tt>=</tt>, and the
683 * associated element, where the <tt>toString</tt> method is used to
684 * convert the key and element to strings. <p>Overrides to
685 * <tt>toString</tt> method of <tt>Object</tt>.
686 *
687 * @return a string representation of this hashtable.
688 */
689 public String toString() {
690 if (count == 0) // read-volatile
691 return "{}";
692
693 StringBuffer buf = new StringBuffer();
694 buf.append("{");
695
696 Entry tab[] = table;
697 int len = tab.length;
698 int k = 0;
699 for (int i = 0 ; i < len; i++) {
700 for (Entry e = tab[i] ; e != null ; e = e.next) {
701 if (k++ != 0)
702 buf.append(", ");
703 Object key = e.getKey();
704 Object value = e.getValue();
705
706 buf.append((key == this ? "(this Map)" : key) + "=" +
707 (value == this ? "(this Map)": value));
708 }
709 }
710 buf.append("}");
711 return buf.toString();
712 }
713
714 /**
715 * Compares the specified Object with this Map for equality,
716 * as per the definition in the Map interface.
717 *
718 * @return true if the specified Object is equal to this Map.
719 * @see Map#equals(Object)
720 * @since 1.2
721 */
722 public boolean equals(Object o) {
723 if (o == this)
724 return true;
725 if (!(o instanceof Map))
726 return false;
727
728 Map t = (Map) o;
729 if (t.size() != count) // read-volatile
730 return false;
731
732 Entry tab[] = table;
733 int len = tab.length;
734 for (int i = 0 ; i < len; i++) {
735 for (Entry e = tab[i] ; e != null ; e = e.next) {
736 Object v = t.get(e.key);
737 if (v == null || !v.equals(e.value))
738 return false;
739 }
740 }
741 return true;
742 }
743
744 /**
745 * Returns the hash code value for this Map as per the definition in the
746 * Map interface.
747 *
748 * @see Map#hashCode()
749 * @since 1.2
750 */
751 public synchronized int hashCode() {
752 /*
753 This implementation maintains compatibility with
754 JDK1.1 to allow computing hashCodes for Hashtables
755 with reference cycles. This requires both synchronization
756 and temporary abuse of the "loadFactor" field to signify
757 that a hashCode is in the midst of being computed so
758 to ignore recursive calls. It is embarassing
759 to use loadFactor in this way, but this tactic permits
760 handling the case without any other field changes.
761
762 Even though hashCodes of cyclic structures can be computed,
763 programs should NOT insert a Hashtable into itself. Because
764 its hashCode changes as a result of entering itself, it is
765 normally impossible to retrieve the embedded Hashtable using
766 get().
767 */
768 int h = 0;
769 float lf = loadFactor;
770 if (count != 0 && lf > 0) {
771 loadFactor = 0; // zero as recursion flag
772 Entry tab[] = table;
773 int len = tab.length;
774 for (int i = 0 ; i < len; i++)
775 for (Entry e = tab[i] ; e != null ; e = e.next)
776 h += e.key.hashCode() ^ e.value.hashCode();
777 loadFactor = lf;
778 }
779 return h;
780 }
781
782
783 /**
784 * Returns a shallow copy of this
785 * <tt>Hashtable</tt> instance: the keys and
786 * values themselves are not cloned.
787 *
788 * @return a shallow copy of this map.
789 */
790 public synchronized Object clone() {
791 Hashtable result = null;
792 try {
793 result = (Hashtable)super.clone();
794 }
795 catch (CloneNotSupportedException e) {
796 // assert false;
797 }
798 result.count = 0;
799 result.keySet = null;
800 result.entrySet = null;
801 result.values = null;
802 result.modCount = 0;
803 result.table = new Entry[table.length];
804 result.putAll(this);
805 return result;
806 }
807
808 /**
809 * Hashtable collision list entry.
810 */
811 private static class Entry implements Map.Entry {
812 private final Object key;
813 private Object value;
814 private final int hash;
815 private final Entry next;
816
817 Entry(int hash, Object key, Object value, Entry next) {
818 this.value = value;
819 this.hash = hash;
820 this.key = key;
821 this.next = next;
822 }
823
824 public Object getKey() {
825 return key;
826 }
827
828 public Object getValue() {
829 return value;
830 }
831
832 public Object setValue(Object newValue) {
833 // We aren't required to, and don't provide any
834 // visibility barriers for setting value.
835 if (newValue == null)
836 throw new NullPointerException();
837 Object oldValue = this.value;
838 this.value = newValue;
839 return oldValue;
840 }
841
842 public boolean equals(Object o) {
843 if (!(o instanceof Map.Entry))
844 return false;
845 Map.Entry e = (Map.Entry)o;
846 return (key.equals(e.getKey()) && value.equals(e.getValue()));
847 }
848
849 public int hashCode() {
850 return key.hashCode() ^ value.hashCode();
851 }
852
853 public String toString() {
854 return key + "=" + value;
855 }
856 }
857
858 /**
859 * Support for Enumeration interface. These Enumerations take a
860 * snapshot of table, so can never encounter corrupted
861 * representations in multithreaded programs. At worst, they will
862 * report the presence of entries deleted since the enumeration
863 * was constructed, or absence of those inserted.
864 */
865 private static class Enumerator implements Enumeration {
866 Entry next; // next entry to return
867 final Entry[] tab; // snapshot of table
868 int index; // current slot
869 final boolean returnKeys;
870
871 Enumerator(boolean returnKeys, int size, Entry[] t) {
872 this.returnKeys = returnKeys;
873 tab = t;
874 int i = t.length;
875 Entry n = null;
876 if (size != 0) { // advance to first entry
877 while (i > 0 && (n = tab[--i]) == null)
878 ;
879 }
880 next = n;
881 index = i;
882 }
883
884 public boolean hasMoreElements() {
885 return next != null;
886 }
887
888 public Object nextElement() {
889 Entry e = next;
890 if (e == null)
891 throw new NoSuchElementException("Hashtable Enumerator");
892
893 Entry n = e.next;
894 int i = index;
895 while (n == null && i > 0)
896 n = tab[--i];
897 index = i;
898 next = n;
899 return returnKeys? e.key : e.value;
900 }
901 }
902
903 private static final int KEYS = 0;
904 private static final int VALUES = 1;
905 private static final int ENTRIES = 2;
906
907 /**
908 * Support for Iterator interface.
909 */
910 private class HashIterator implements Iterator {
911 Entry next; // next entry to return
912 int expectedModCount; // For fast-fail
913 int index; // current slot
914 Entry current; // current entry
915 final int returnType; // KEYS or VALUES or ENTRIES
916
917 HashIterator(int returnType) {
918 this.returnType = returnType;
919 int size = count; // read-volatile
920 Entry[] t = table;
921 expectedModCount = modCount;
922 int i = t.length;
923 Entry n = null;
924 if (size != 0) { // advance to first entry
925 while (i > 0 && (n = t[--i]) == null)
926 ;
927 }
928 next = n;
929 index = i;
930 }
931
932 public boolean hasNext() {
933 return next != null;
934 }
935
936 public Object next() {
937 int ignore = count; // read-volatile
938 if (modCount != expectedModCount)
939 throw new ConcurrentModificationException();
940 Entry e = next;
941 if (e == null)
942 throw new NoSuchElementException("Hashtable Enumerator");
943
944 Entry n = e.next;
945 Entry[] t = table;
946 int i = index;
947 while (n == null && i > 0)
948 n = t[--i];
949 index = i;
950 next = n;
951 current = e;
952 return (returnType == KEYS)? e.key :
953 ((returnType == VALUES)? e.value : e);
954 }
955
956 public void remove() {
957 if (current == null)
958 throw new IllegalStateException("Hashtable Enumerator");
959 Object k = current.key;
960 current = null;
961 if (Hashtable.this.remove(k) == null)
962 throw new ConcurrentModificationException();
963 expectedModCount = modCount;
964 }
965 }
966
967
968 // Views
969
970 private transient Set keySet = null;
971 private transient Set entrySet = null;
972 private transient Collection values = null;
973
974 /**
975 * Returns a set view of the keys contained in this map. The set is
976 * backed by the map, so changes to the map are reflected in the set, and
977 * vice-versa. The set supports element removal, which removes the
978 * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
979 * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
980 * <tt>clear</tt> operations. It does not support the <tt>add</tt> or
981 * <tt>addAll</tt> operations.
982 *
983 * @return a set view of the keys contained in this map.
984 */
985
986 public Set keySet() {
987 Set ks = keySet;
988 return (ks != null)? ks : (keySet = new KeySet());
989 }
990
991 private class KeySet extends AbstractSet {
992 public Iterator iterator() {
993 return new HashIterator(KEYS);
994 }
995 public int size() {
996 return Hashtable.this.size();
997 }
998 public boolean contains(Object o) {
999 return Hashtable.this.containsKey(o);
1000 }
1001 public boolean remove(Object o) {
1002 return Hashtable.this.remove(o) != null;
1003 }
1004 public void clear() {
1005 Hashtable.this.clear();
1006 }
1007 }
1008
1009 /**
1010 * Returns a collection view of the values contained in this map. The
1011 * collection is backed by the map, so changes to the map are reflected in
1012 * the collection, and vice-versa. The collection supports element
1013 * removal, which removes the corresponding mapping from this map, via the
1014 * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
1015 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
1016 * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
1017 *
1018 * @return a collection view of the values contained in this map.
1019 */
1020
1021 public Collection values() {
1022 Collection vs = values;
1023 return (vs != null)? vs : (values = new Values());
1024 }
1025
1026 private class Values extends AbstractCollection {
1027 public Iterator iterator() {
1028 return new HashIterator(VALUES);
1029 }
1030 public int size() {
1031 return Hashtable.this.size();
1032 }
1033 public boolean contains(Object o) {
1034 return Hashtable.this.containsValue(o);
1035 }
1036 public void clear() {
1037 Hashtable.this.clear();
1038 }
1039 }
1040
1041 /**
1042 * Returns a collection view of the mappings contained in this map. Each
1043 * element in the returned collection is a <tt>Map.Entry</tt>. The
1044 * collection is backed by the map, so changes to the map are reflected in
1045 * the collection, and vice-versa. The collection supports element
1046 * removal, which removes the corresponding mapping from the map, via the
1047 * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
1048 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
1049 * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
1050 *
1051 * @return a collection view of the mappings contained in this map.
1052 * @see Map.Entry
1053 */
1054
1055 public Set entrySet() {
1056 Set es = entrySet;
1057 return (es != null) ? es : (entrySet = new EntrySet());
1058 }
1059
1060 private class EntrySet extends AbstractSet {
1061 public Iterator iterator() {
1062 return new HashIterator(ENTRIES);
1063 }
1064 public boolean contains(Object o) {
1065 if (!(o instanceof Map.Entry))
1066 return false;
1067 Map.Entry entry = (Map.Entry)o;
1068 Object v = Hashtable.this.get(entry.getKey());
1069 return v != null && v.equals(entry.getValue());
1070 }
1071 public boolean remove(Object o) {
1072 if (!(o instanceof Map.Entry))
1073 return false;
1074 Map.Entry entry = (Map.Entry)o;
1075 return Hashtable.this.findAndRemoveEntry(entry.getKey(),
1076 entry.getValue());
1077 }
1078 public int size() {
1079 return Hashtable.this.size();
1080 }
1081 public void clear() {
1082 Hashtable.this.clear();
1083 }
1084 }
1085
1086 /**
1087 * Returns an enumeration of the keys in this table.
1088 *
1089 * @return an enumeration of the keys in this table.
1090 * @see Enumeration
1091 * @see #elements()
1092 * @see #keySet()
1093 * @see Map
1094 */
1095 public Enumeration keys() {
1096 int n = count; // read-volatile
1097 return new Enumerator(true, n, table);
1098 }
1099
1100 /**
1101 * Returns an enumeration of the values in this table.
1102 * Use the Enumeration methods on the returned object to fetch the elements
1103 * sequentially.
1104 *
1105 * @return an enumeration of the values in this table.
1106 * @see java.util.Enumeration
1107 * @see #keys()
1108 * @see #values()
1109 * @see Map
1110 */
1111
1112 public Enumeration elements() {
1113 int n = count; // read-volatile
1114 return new Enumerator(false, n, table);
1115 }
1116
1117 /**
1118 * Save the state of the <tt>Hashtable</tt>
1119 * instance to a stream (i.e.,
1120 * serialize it).
1121 *
1122 * @serialData The <i>capacity</i> of the
1123 * Hashtable (the length of the
1124 * bucket array) is emitted (int), followed by the
1125 * <i>size</i> of the Hashtable (the number of key-value
1126 * mappings), followed by the key (Object) and value (Object)
1127 * for each key-value mapping represented by the Hashtable
1128 * The key-value mappings are emitted in no particular order.
1129 */
1130
1131 private synchronized void writeObject(java.io.ObjectOutputStream s)
1132 throws IOException {
1133 // Write out the threshold, loadfactor, and any hidden stuff
1134 s.defaultWriteObject();
1135
1136 // Write out number of buckets
1137 s.writeInt(table.length);
1138
1139 // Write out size (number of Mappings)
1140 s.writeInt(count);
1141
1142 // Write out keys and values (alternating)
1143 for (int index = table.length-1; index >= 0; index--) {
1144 Entry entry = table[index];
1145
1146 while (entry != null) {
1147 s.writeObject(entry.key);
1148 s.writeObject(entry.value);
1149 entry = entry.next;
1150 }
1151 }
1152 }
1153
1154 /**
1155 * Reconstitute the <tt>Hashtable</tt>
1156 * instance from a stream (i.e.,
1157 * deserialize it).
1158 */
1159 private synchronized void readObject(java.io.ObjectInputStream s)
1160 throws IOException, ClassNotFoundException {
1161 // Read in the threshold, loadfactor, and any hidden stuff
1162 s.defaultReadObject();
1163
1164 // Read in number of buckets and allocate the bucket array;
1165 int numBuckets = s.readInt();
1166 table = new Entry[numBuckets];
1167
1168 // Read in size (number of Mappings)
1169 int size = s.readInt();
1170
1171 // Read the keys and values, and put the mappings in the table
1172 for (int i=0; i<size; i++) {
1173 Object key = s.readObject();
1174 Object value = s.readObject();
1175 put(key, value);
1176 }
1177 }
1178
1179 }