ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/Hashtable.java
Revision: 1.1
Committed: Wed May 14 21:30:44 2003 UTC (21 years ago) by tim
Branch: MAIN
Log Message:
Moved main source rooted at . to ./src/main
Moved test source rooted at ./etc/testcases to ./src/test

File Contents

# User Rev Content
1 tim 1.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     }