1 /*
2  * Copyright (c) 1994, 2018, Oracle and/or its affiliates. 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */

25
26 package java.util;
27
28 import java.io.*;
29 import java.util.function.BiConsumer;
30 import java.util.function.Function;
31 import java.util.function.BiFunction;
32 import jdk.internal.misc.SharedSecrets;
33
34 /**
35  * This class implements a hash table, which maps keys to values. Any
36  * non-{@code null} object can be used as a key or as a value. <p>
37  *
38  * To successfully store and retrieve objects from a hashtable, the
39  * objects used as keys must implement the {@code hashCode}
40  * method and the {@code equals} method. <p>
41  *
42  * An instance of {@code Hashtable} has two parameters that affect its
43  * performance: <i>initial capacity</i> and <i>load factor</i>.  The
44  * <i>capacity</i> is the number of <i>buckets</i> in the hash table, and the
45  * <i>initial capacity</i> is simply the capacity at the time the hash table
46  * is created.  Note that the hash table is <i>open</i>: in the case of a "hash
47  * collision", a single bucket stores multiple entries, which must be searched
48  * sequentially.  The <i>load factor</i> is a measure of how full the hash
49  * table is allowed to get before its capacity is automatically increased.
50  * The initial capacity and load factor parameters are merely hints to
51  * the implementation.  The exact details as to when and whether the rehash
52  * method is invoked are implementation-dependent.<p>
53  *
54  * Generally, the default load factor (.75) offers a good tradeoff between
55  * time and space costs.  Higher values decrease the space overhead but
56  * increase the time cost to look up an entry (which is reflected in most
57  * {@code Hashtable} operations, including {@code get} and {@code put}).<p>
58  *
59  * The initial capacity controls a tradeoff between wasted space and the
60  * need for {@code rehash} operations, which are time-consuming.
61  * No {@code rehash} operations will <i>ever</i> occur if the initial
62  * capacity is greater than the maximum number of entries the
63  * {@code Hashtable} will contain divided by its load factor.  However,
64  * setting the initial capacity too high can waste space.<p>
65  *
66  * If many entries are to be made into a {@code Hashtable},
67  * creating it with a sufficiently large capacity may allow the
68  * entries to be inserted more efficiently than letting it perform
69  * automatic rehashing as needed to grow the table. <p>
70  *
71  * This example creates a hashtable of numbers. It uses the names of
72  * the numbers as keys:
73  * <pre>   {@code
74  *   Hashtable<String, Integer> numbers
75  *     = new Hashtable<String, Integer>();
76  *   numbers.put("one", 1);
77  *   numbers.put("two", 2);
78  *   numbers.put("three", 3);}</pre>
79  *
80  * <p>To retrieve a number, use the following code:
81  * <pre>   {@code
82  *   Integer n = numbers.get("two");
83  *   if (n != null) {
84  *     System.out.println("two = " + n);
85  *   }}</pre>
86  *
87  * <p>The iterators returned by the {@code iterator} method of the collections
88  * returned by all of this class's "collection view methods" are
89  * <em>fail-fast</em>: if the Hashtable is structurally modified at any time
90  * after the iterator is created, in any way except through the iterator's own
91  * {@code remove} method, the iterator will throw a {@link
92  * ConcurrentModificationException}.  Thus, in the face of concurrent
93  * modification, the iterator fails quickly and cleanly, rather than risking
94  * arbitrary, non-deterministic behavior at an undetermined time in the future.
95  * The Enumerations returned by Hashtable's {@link #keys keys} and
96  * {@link #elements elements} methods are <em>not</em> fail-fast; if the
97  * Hashtable is structurally modified at any time after the enumeration is
98  * created then the results of enumerating are undefined.
99  *
100  * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
101  * as it is, generally speaking, impossible to make any hard guarantees in the
102  * presence of unsynchronized concurrent modification.  Fail-fast iterators
103  * throw {@code ConcurrentModificationException} on a best-effort basis.
104  * Therefore, it would be wrong to write a program that depended on this
105  * exception for its correctness: <i>the fail-fast behavior of iterators
106  * should be used only to detect bugs.</i>
107  *
108  * <p>As of the Java 2 platform v1.2, this class was retrofitted to
109  * implement the {@link Map} interface, making it a member of the
110  * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
111  *
112  * Java Collections Framework</a>.  Unlike the new collection
113  * implementations, {@code Hashtable} is synchronized.  If a
114  * thread-safe implementation is not needed, it is recommended to use
115  * {@link HashMap} in place of {@code Hashtable}.  If a thread-safe
116  * highly-concurrent implementation is desired, then it is recommended
117  * to use {@link java.util.concurrent.ConcurrentHashMap} in place of
118  * {@code Hashtable}.
119  *
120  * @param <K> the type of keys maintained by this map
121  * @param <V> the type of mapped values
122  *
123  * @author  Arthur van Hoff
124  * @author  Josh Bloch
125  * @author  Neal Gafter
126  * @see     Object#equals(java.lang.Object)
127  * @see     Object#hashCode()
128  * @see     Hashtable#rehash()
129  * @see     Collection
130  * @see     Map
131  * @see     HashMap
132  * @see     TreeMap
133  * @since 1.0
134  */

135 public class Hashtable<K,V>
136     extends Dictionary<K,V>
137     implements Map<K,V>, Cloneable, java.io.Serializable {
138
139     /**
140      * The hash table data.
141      */

142     private transient Entry<?,?>[] table;
143
144     /**
145      * The total number of entries in the hash table.
146      */

147     private transient int count;
148
149     /**
150      * The table is rehashed when its size exceeds this threshold.  (The
151      * value of this field is (int)(capacity * loadFactor).)
152      *
153      * @serial
154      */

155     private int threshold;
156
157     /**
158      * The load factor for the hashtable.
159      *
160      * @serial
161      */

162     private float loadFactor;
163
164     /**
165      * The number of times this Hashtable has been structurally modified
166      * Structural modifications are those that change the number of entries in
167      * the Hashtable or otherwise modify its internal structure (e.g.,
168      * rehash).  This field is used to make iterators on Collection-views of
169      * the Hashtable fail-fast.  (See ConcurrentModificationException).
170      */

171     private transient int modCount = 0;
172
173     /** use serialVersionUID from JDK 1.0.2 for interoperability */
174     private static final long serialVersionUID = 1421746759512286392L;
175
176     /**
177      * Constructs a new, empty hashtable with the specified initial
178      * capacity and the specified load factor.
179      *
180      * @param      initialCapacity   the initial capacity of the hashtable.
181      * @param      loadFactor        the load factor of the hashtable.
182      * @exception  IllegalArgumentException  if the initial capacity is less
183      *             than zero, or if the load factor is nonpositive.
184      */

185     public Hashtable(int initialCapacity, float loadFactor) {
186         if (initialCapacity < 0)
187             throw new IllegalArgumentException("Illegal Capacity: "+
188                                                initialCapacity);
189         if (loadFactor <= 0 || Float.isNaN(loadFactor))
190             throw new IllegalArgumentException("Illegal Load: "+loadFactor);
191
192         if (initialCapacity==0)
193             initialCapacity = 1;
194         this.loadFactor = loadFactor;
195         table = new Entry<?,?>[initialCapacity];
196         threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
197     }
198
199     /**
200      * Constructs a new, empty hashtable with the specified initial capacity
201      * and default load factor (0.75).
202      *
203      * @param     initialCapacity   the initial capacity of the hashtable.
204      * @exception IllegalArgumentException if the initial capacity is less
205      *              than zero.
206      */

207     public Hashtable(int initialCapacity) {
208         this(initialCapacity, 0.75f);
209     }
210
211     /**
212      * Constructs a new, empty hashtable with a default initial capacity (11)
213      * and load factor (0.75).
214      */

215     public Hashtable() {
216         this(11, 0.75f);
217     }
218
219     /**
220      * Constructs a new hashtable with the same mappings as the given
221      * Map.  The hashtable is created with an initial capacity sufficient to
222      * hold the mappings in the given Map and a default load factor (0.75).
223      *
224      * @param t the map whose mappings are to be placed in this map.
225      * @throws NullPointerException if the specified map is null.
226      * @since   1.2
227      */

228     public Hashtable(Map<? extends K, ? extends V> t) {
229         this(Math.max(2*t.size(), 11), 0.75f);
230         putAll(t);
231     }
232
233     /**
234      * A constructor chained from {@link Properties} keeps Hashtable fields
235      * uninitialized since they are not used.
236      *
237      * @param dummy a dummy parameter
238      */

239     Hashtable(Void dummy) {}
240
241     /**
242      * Returns the number of keys in this hashtable.
243      *
244      * @return  the number of keys in this hashtable.
245      */

246     public synchronized int size() {
247         return count;
248     }
249
250     /**
251      * Tests if this hashtable maps no keys to values.
252      *
253      * @return  {@code trueif this hashtable maps no keys to values;
254      *          {@code false} otherwise.
255      */

256     public synchronized boolean isEmpty() {
257         return count == 0;
258     }
259
260     /**
261      * Returns an enumeration of the keys in this hashtable.
262      * Use the Enumeration methods on the returned object to fetch the keys
263      * sequentially. If the hashtable is structurally modified while enumerating
264      * over the keys then the results of enumerating are undefined.
265      *
266      * @return  an enumeration of the keys in this hashtable.
267      * @see     Enumeration
268      * @see     #elements()
269      * @see     #keySet()
270      * @see     Map
271      */

272     public synchronized Enumeration<K> keys() {
273         return this.<K>getEnumeration(KEYS);
274     }
275
276     /**
277      * Returns an enumeration of the values in this hashtable.
278      * Use the Enumeration methods on the returned object to fetch the elements
279      * sequentially. If the hashtable is structurally modified while enumerating
280      * over the values then the results of enumerating are undefined.
281      *
282      * @return  an enumeration of the values in this hashtable.
283      * @see     java.util.Enumeration
284      * @see     #keys()
285      * @see     #values()
286      * @see     Map
287      */

288     public synchronized Enumeration<V> elements() {
289         return this.<V>getEnumeration(VALUES);
290     }
291
292     /**
293      * Tests if some key maps into the specified value in this hashtable.
294      * This operation is more expensive than the {@link #containsKey
295      * containsKey} method.
296      *
297      * <p>Note that this method is identical in functionality to
298      * {@link #containsValue containsValue}, (which is part of the
299      * {@link Map} interface in the collections framework).
300      *
301      * @param      value   a value to search for
302      * @return     {@code trueif and only if some key maps to the
303      *             {@code value} argument in this hashtable as
304      *             determined by the {@code equals} method;
305      *             {@code false} otherwise.
306      * @exception  NullPointerException  if the value is {@code null}
307      */

308     public synchronized boolean contains(Object value) {
309         if (value == null) {
310             throw new NullPointerException();
311         }
312
313         Entry<?,?> tab[] = table;
314         for (int i = tab.length ; i-- > 0 ;) {
315             for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
316                 if (e.value.equals(value)) {
317                     return true;
318                 }
319             }
320         }
321         return false;
322     }
323
324     /**
325      * Returns true if this hashtable maps one or more keys to this value.
326      *
327      * <p>Note that this method is identical in functionality to {@link
328      * #contains contains} (which predates the {@link Map} interface).
329      *
330      * @param value value whose presence in this hashtable is to be tested
331      * @return {@code trueif this map maps one or more keys to the
332      *         specified value
333      * @throws NullPointerException  if the value is {@code null}
334      * @since 1.2
335      */

336     public boolean containsValue(Object value) {
337         return contains(value);
338     }
339
340     /**
341      * Tests if the specified object is a key in this hashtable.
342      *
343      * @param   key   possible key
344      * @return  {@code trueif and only if the specified object
345      *          is a key in this hashtable, as determined by the
346      *          {@code equals} method; {@code false} otherwise.
347      * @throws  NullPointerException  if the key is {@code null}
348      * @see     #contains(Object)
349      */

350     public synchronized boolean containsKey(Object key) {
351         Entry<?,?> tab[] = table;
352         int hash = key.hashCode();
353         int index = (hash & 0x7FFFFFFF) % tab.length;
354         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
355             if ((e.hash == hash) && e.key.equals(key)) {
356                 return true;
357             }
358         }
359         return false;
360     }
361
362     /**
363      * Returns the value to which the specified key is mapped,
364      * or {@code nullif this map contains no mapping for the key.
365      *
366      * <p>More formally, if this map contains a mapping from a key
367      * {@code k} to a value {@code v} such that {@code (key.equals(k))},
368      * then this method returns {@code v}; otherwise it returns
369      * {@code null}.  (There can be at most one such mapping.)
370      *
371      * @param key the key whose associated value is to be returned
372      * @return the value to which the specified key is mapped, or
373      *         {@code nullif this map contains no mapping for the key
374      * @throws NullPointerException if the specified key is null
375      * @see     #put(Object, Object)
376      */

377     @SuppressWarnings("unchecked")
378     public synchronized V get(Object key) {
379         Entry<?,?> tab[] = table;
380         int hash = key.hashCode();
381         int index = (hash & 0x7FFFFFFF) % tab.length;
382         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
383             if ((e.hash == hash) && e.key.equals(key)) {
384                 return (V)e.value;
385             }
386         }
387         return null;
388     }
389
390     /**
391      * The maximum size of array to allocate.
392      * Some VMs reserve some header words in an array.
393      * Attempts to allocate larger arrays may result in
394      * OutOfMemoryError: Requested array size exceeds VM limit
395      */

396     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
397
398     /**
399      * Increases the capacity of and internally reorganizes this
400      * hashtable, in order to accommodate and access its entries more
401      * efficiently.  This method is called automatically when the
402      * number of keys in the hashtable exceeds this hashtable's capacity
403      * and load factor.
404      */

405     @SuppressWarnings("unchecked")
406     protected void rehash() {
407         int oldCapacity = table.length;
408         Entry<?,?>[] oldMap = table;
409
410         // overflow-conscious code
411         int newCapacity = (oldCapacity << 1) + 1;
412         if (newCapacity - MAX_ARRAY_SIZE > 0) {
413             if (oldCapacity == MAX_ARRAY_SIZE)
414                 // Keep running with MAX_ARRAY_SIZE buckets
415                 return;
416             newCapacity = MAX_ARRAY_SIZE;
417         }
418         Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
419
420         modCount++;
421         threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
422         table = newMap;
423
424         for (int i = oldCapacity ; i-- > 0 ;) {
425             for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
426                 Entry<K,V> e = old;
427                 old = old.next;
428
429                 int index = (e.hash & 0x7FFFFFFF) % newCapacity;
430                 e.next = (Entry<K,V>)newMap[index];
431                 newMap[index] = e;
432             }
433         }
434     }
435
436     private void addEntry(int hash, K key, V value, int index) {
437         Entry<?,?> tab[] = table;
438         if (count >= threshold) {
439             // Rehash the table if the threshold is exceeded
440             rehash();
441
442             tab = table;
443             hash = key.hashCode();
444             index = (hash & 0x7FFFFFFF) % tab.length;
445         }
446
447         // Creates the new entry.
448         @SuppressWarnings("unchecked")
449         Entry<K,V> e = (Entry<K,V>) tab[index];
450         tab[index] = new Entry<>(hash, key, value, e);
451         count++;
452         modCount++;
453     }
454
455     /**
456      * Maps the specified {@code key} to the specified
457      * {@code value} in this hashtable. Neither the key nor the
458      * value can be {@code null}. <p>
459      *
460      * The value can be retrieved by calling the {@code get} method
461      * with a key that is equal to the original key.
462      *
463      * @param      key     the hashtable key
464      * @param      value   the value
465      * @return     the previous value of the specified key in this hashtable,
466      *             or {@code nullif it did not have one
467      * @exception  NullPointerException  if the key or value is
468      *               {@code null}
469      * @see     Object#equals(Object)
470      * @see     #get(Object)
471      */

472     public synchronized V put(K key, V value) {
473         // Make sure the value is not null
474         if (value == null) {
475             throw new NullPointerException();
476         }
477
478         // Makes sure the key is not already in the hashtable.
479         Entry<?,?> tab[] = table;
480         int hash = key.hashCode();
481         int index = (hash & 0x7FFFFFFF) % tab.length;
482         @SuppressWarnings("unchecked")
483         Entry<K,V> entry = (Entry<K,V>)tab[index];
484         for(; entry != null ; entry = entry.next) {
485             if ((entry.hash == hash) && entry.key.equals(key)) {
486                 V old = entry.value;
487                 entry.value = value;
488                 return old;
489             }
490         }
491
492         addEntry(hash, key, value, index);
493         return null;
494     }
495
496     /**
497      * Removes the key (and its corresponding value) from this
498      * hashtable. This method does nothing if the key is not in the hashtable.
499      *
500      * @param   key   the key that needs to be removed
501      * @return  the value to which the key had been mapped in this hashtable,
502      *          or {@code nullif the key did not have a mapping
503      * @throws  NullPointerException  if the key is {@code null}
504      */

505     public synchronized V remove(Object key) {
506         Entry<?,?> tab[] = table;
507         int hash = key.hashCode();
508         int index = (hash & 0x7FFFFFFF) % tab.length;
509         @SuppressWarnings("unchecked")
510         Entry<K,V> e = (Entry<K,V>)tab[index];
511         for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
512             if ((e.hash == hash) && e.key.equals(key)) {
513                 if (prev != null) {
514                     prev.next = e.next;
515                 } else {
516                     tab[index] = e.next;
517                 }
518                 modCount++;
519                 count--;
520                 V oldValue = e.value;
521                 e.value = null;
522                 return oldValue;
523             }
524         }
525         return null;
526     }
527
528     /**
529      * Copies all of the mappings from the specified map to this hashtable.
530      * These mappings will replace any mappings that this hashtable had for any
531      * of the keys currently in the specified map.
532      *
533      * @param t mappings to be stored in this map
534      * @throws NullPointerException if the specified map is null
535      * @since 1.2
536      */

537     public synchronized void putAll(Map<? extends K, ? extends V> t) {
538         for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
539             put(e.getKey(), e.getValue());
540     }
541
542     /**
543      * Clears this hashtable so that it contains no keys.
544      */

545     public synchronized void clear() {
546         Entry<?,?> tab[] = table;
547         for (int index = tab.length; --index >= 0; )
548             tab[index] = null;
549         modCount++;
550         count = 0;
551     }
552
553     /**
554      * Creates a shallow copy of this hashtable. All the structure of the
555      * hashtable itself is copied, but the keys and values are not cloned.
556      * This is a relatively expensive operation.
557      *
558      * @return  a clone of the hashtable
559      */

560     public synchronized Object clone() {
561         Hashtable<?,?> t = cloneHashtable();
562         t.table = new Entry<?,?>[table.length];
563         for (int i = table.length ; i-- > 0 ; ) {
564             t.table[i] = (table[i] != null)
565                 ? (Entry<?,?>) table[i].clone() : null;
566         }
567         t.keySet = null;
568         t.entrySet = null;
569         t.values = null;
570         t.modCount = 0;
571         return t;
572     }
573
574     /** Calls super.clone() */
575     final Hashtable<?,?> cloneHashtable() {
576         try {
577             return (Hashtable<?,?>)super.clone();
578         } catch (CloneNotSupportedException e) {
579             // this shouldn't happen, since we are Cloneable
580             throw new InternalError(e);
581         }
582     }
583
584     /**
585      * Returns a string representation of this {@code Hashtable} object
586      * in the form of a set of entries, enclosed in braces and separated
587      * by the ASCII characters "<code> ,&nbsp;</code>" (comma and space). Each
588      * entry is rendered as the key, an equals sign {@code =}, and the
589      * associated element, where the {@code toString} method is used to
590      * convert the key and element to strings.
591      *
592      * @return  a string representation of this hashtable
593      */

594     public synchronized String toString() {
595         int max = size() - 1;
596         if (max == -1)
597             return "{}";
598
599         StringBuilder sb = new StringBuilder();
600         Iterator<Map.Entry<K,V>> it = entrySet().iterator();
601
602         sb.append('{');
603         for (int i = 0; ; i++) {
604             Map.Entry<K,V> e = it.next();
605             K key = e.getKey();
606             V value = e.getValue();
607             sb.append(key   == this ? "(this Map)" : key.toString());
608             sb.append('=');
609             sb.append(value == this ? "(this Map)" : value.toString());
610
611             if (i == max)
612                 return sb.append('}').toString();
613             sb.append(", ");
614         }
615     }
616
617
618     private <T> Enumeration<T> getEnumeration(int type) {
619         if (count == 0) {
620             return Collections.emptyEnumeration();
621         } else {
622             return new Enumerator<>(type, false);
623         }
624     }
625
626     private <T> Iterator<T> getIterator(int type) {
627         if (count == 0) {
628             return Collections.emptyIterator();
629         } else {
630             return new Enumerator<>(type, true);
631         }
632     }
633
634     // Views
635
636     /**
637      * Each of these fields are initialized to contain an instance of the
638      * appropriate view the first time this view is requested.  The views are
639      * stateless, so there's no reason to create more than one of each.
640      */

641     private transient volatile Set<K> keySet;
642     private transient volatile Set<Map.Entry<K,V>> entrySet;
643     private transient volatile Collection<V> values;
644
645     /**
646      * Returns a {@link Set} view of the keys contained in this map.
647      * The set is backed by the map, so changes to the map are
648      * reflected in the set, and vice-versa.  If the map is modified
649      * while an iteration over the set is in progress (except through
650      * the iterator's own {@code remove} operation), the results of
651      * the iteration are undefined.  The set supports element removal,
652      * which removes the corresponding mapping from the map, via the
653      * {@code Iterator.remove}, {@code Set.remove},
654      * {@code removeAll}, {@code retainAll}, and {@code clear}
655      * operations.  It does not support the {@code add} or {@code addAll}
656      * operations.
657      *
658      * @since 1.2
659      */

660     public Set<K> keySet() {
661         if (keySet == null)
662             keySet = Collections.synchronizedSet(new KeySet(), this);
663         return keySet;
664     }
665
666     private class KeySet extends AbstractSet<K> {
667         public Iterator<K> iterator() {
668             return getIterator(KEYS);
669         }
670         public int size() {
671             return count;
672         }
673         public boolean contains(Object o) {
674             return containsKey(o);
675         }
676         public boolean remove(Object o) {
677             return Hashtable.this.remove(o) != null;
678         }
679         public void clear() {
680             Hashtable.this.clear();
681         }
682     }
683
684     /**
685      * Returns a {@link Set} view of the mappings contained in this map.
686      * The set is backed by the map, so changes to the map are
687      * reflected in the set, and vice-versa.  If the map is modified
688      * while an iteration over the set is in progress (except through
689      * the iterator's own {@code remove} operation, or through the
690      * {@code setValue} operation on a map entry returned by the
691      * iterator) the results of the iteration are undefined.  The set
692      * supports element removal, which removes the corresponding
693      * mapping from the map, via the {@code Iterator.remove},
694      * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
695      * {@code clear} operations.  It does not support the
696      * {@code add} or {@code addAll} operations.
697      *
698      * @since 1.2
699      */

700     public Set<Map.Entry<K,V>> entrySet() {
701         if (entrySet==null)
702             entrySet = Collections.synchronizedSet(new EntrySet(), this);
703         return entrySet;
704     }
705
706     private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
707         public Iterator<Map.Entry<K,V>> iterator() {
708             return getIterator(ENTRIES);
709         }
710
711         public boolean add(Map.Entry<K,V> o) {
712             return super.add(o);
713         }
714
715         public boolean contains(Object o) {
716             if (!(o instanceof Map.Entry))
717                 return false;
718             Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
719             Object key = entry.getKey();
720             Entry<?,?>[] tab = table;
721             int hash = key.hashCode();
722             int index = (hash & 0x7FFFFFFF) % tab.length;
723
724             for (Entry<?,?> e = tab[index]; e != null; e = e.next)
725                 if (e.hash==hash && e.equals(entry))
726                     return true;
727             return false;
728         }
729
730         public boolean remove(Object o) {
731             if (!(o instanceof Map.Entry))
732                 return false;
733             Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
734             Object key = entry.getKey();
735             Entry<?,?>[] tab = table;
736             int hash = key.hashCode();
737             int index = (hash & 0x7FFFFFFF) % tab.length;
738
739             @SuppressWarnings("unchecked")
740             Entry<K,V> e = (Entry<K,V>)tab[index];
741             for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
742                 if (e.hash==hash && e.equals(entry)) {
743                     if (prev != null)
744                         prev.next = e.next;
745                     else
746                         tab[index] = e.next;
747
748                     e.value = null// clear for gc.
749                     modCount++;
750                     count--;
751                     return true;
752                 }
753             }
754             return false;
755         }
756
757         public int size() {
758             return count;
759         }
760
761         public void clear() {
762             Hashtable.this.clear();
763         }
764     }
765
766     /**
767      * Returns a {@link Collection} view of the values contained in this map.
768      * The collection is backed by the map, so changes to the map are
769      * reflected in the collection, and vice-versa.  If the map is
770      * modified while an iteration over the collection is in progress
771      * (except through the iterator's own {@code remove} operation),
772      * the results of the iteration are undefined.  The collection
773      * supports element removal, which removes the corresponding
774      * mapping from the map, via the {@code Iterator.remove},
775      * {@code Collection.remove}, {@code removeAll},
776      * {@code retainAll} and {@code clear} operations.  It does not
777      * support the {@code add} or {@code addAll} operations.
778      *
779      * @since 1.2
780      */

781     public Collection<V> values() {
782         if (values==null)
783             values = Collections.synchronizedCollection(new ValueCollection(),
784                                                         this);
785         return values;
786     }
787
788     private class ValueCollection extends AbstractCollection<V> {
789         public Iterator<V> iterator() {
790             return getIterator(VALUES);
791         }
792         public int size() {
793             return count;
794         }
795         public boolean contains(Object o) {
796             return containsValue(o);
797         }
798         public void clear() {
799             Hashtable.this.clear();
800         }
801     }
802
803     // Comparison and hashing
804
805     /**
806      * Compares the specified Object with this Map for equality,
807      * as per the definition in the Map interface.
808      *
809      * @param  o object to be compared for equality with this hashtable
810      * @return true if the specified Object is equal to this Map
811      * @see Map#equals(Object)
812      * @since 1.2
813      */

814     public synchronized boolean equals(Object o) {
815         if (o == this)
816             return true;
817
818         if (!(o instanceof Map))
819             return false;
820         Map<?,?> t = (Map<?,?>) o;
821         if (t.size() != size())
822             return false;
823
824         try {
825             for (Map.Entry<K, V> e : entrySet()) {
826                 K key = e.getKey();
827                 V value = e.getValue();
828                 if (value == null) {
829                     if (!(t.get(key) == null && t.containsKey(key)))
830                         return false;
831                 } else {
832                     if (!value.equals(t.get(key)))
833                         return false;
834                 }
835             }
836         } catch (ClassCastException unused)   {
837             return false;
838         } catch (NullPointerException unused) {
839             return false;
840         }
841
842         return true;
843     }
844
845     /**
846      * Returns the hash code value for this Map as per the definition in the
847      * Map interface.
848      *
849      * @see Map#hashCode()
850      * @since 1.2
851      */

852     public synchronized int hashCode() {
853         /*
854          * This code detects the recursion caused by computing the hash code
855          * of a self-referential hash table and prevents the stack overflow
856          * that would otherwise result.  This allows certain 1.1-era
857          * applets with self-referential hash tables to work.  This code
858          * abuses the loadFactor field to do double-duty as a hashCode
859          * in progress flag, so as not to worsen the space performance.
860          * A negative load factor indicates that hash code computation is
861          * in progress.
862          */

863         int h = 0;
864         if (count == 0 || loadFactor < 0)
865             return h;  // Returns zero
866
867         loadFactor = -loadFactor;  // Mark hashCode computation in progress
868         Entry<?,?>[] tab = table;
869         for (Entry<?,?> entry : tab) {
870             while (entry != null) {
871                 h += entry.hashCode();
872                 entry = entry.next;
873             }
874         }
875
876         loadFactor = -loadFactor;  // Mark hashCode computation complete
877
878         return h;
879     }
880
881     @Override
882     public synchronized V getOrDefault(Object key, V defaultValue) {
883         V result = get(key);
884         return (null == result) ? defaultValue : result;
885     }
886
887     @SuppressWarnings("unchecked")
888     @Override
889     public synchronized void forEach(BiConsumer<? super K, ? super V> action) {
890         Objects.requireNonNull(action);     // explicit check required in case
891                                             // table is empty.
892         final int expectedModCount = modCount;
893
894         Entry<?, ?>[] tab = table;
895         for (Entry<?, ?> entry : tab) {
896             while (entry != null) {
897                 action.accept((K)entry.key, (V)entry.value);
898                 entry = entry.next;
899
900                 if (expectedModCount != modCount) {
901                     throw new ConcurrentModificationException();
902                 }
903             }
904         }
905     }
906
907     @SuppressWarnings("unchecked")
908     @Override
909     public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
910         Objects.requireNonNull(function);     // explicit check required in case
911                                               // table is empty.
912         final int expectedModCount = modCount;
913
914         Entry<K, V>[] tab = (Entry<K, V>[])table;
915         for (Entry<K, V> entry : tab) {
916             while (entry != null) {
917                 entry.value = Objects.requireNonNull(
918                     function.apply(entry.key, entry.value));
919                 entry = entry.next;
920
921                 if (expectedModCount != modCount) {
922                     throw new ConcurrentModificationException();
923                 }
924             }
925         }
926     }
927
928     @Override
929     public synchronized V putIfAbsent(K key, V value) {
930         Objects.requireNonNull(value);
931
932         // Makes sure the key is not already in the hashtable.
933         Entry<?,?> tab[] = table;
934         int hash = key.hashCode();
935         int index = (hash & 0x7FFFFFFF) % tab.length;
936         @SuppressWarnings("unchecked")
937         Entry<K,V> entry = (Entry<K,V>)tab[index];
938         for (; entry != null; entry = entry.next) {
939             if ((entry.hash == hash) && entry.key.equals(key)) {
940                 V old = entry.value;
941                 if (old == null) {
942                     entry.value = value;
943                 }
944                 return old;
945             }
946         }
947
948         addEntry(hash, key, value, index);
949         return null;
950     }
951
952     @Override
953     public synchronized boolean remove(Object key, Object value) {
954         Objects.requireNonNull(value);
955
956         Entry<?,?> tab[] = table;
957         int hash = key.hashCode();
958         int index = (hash & 0x7FFFFFFF) % tab.length;
959         @SuppressWarnings("unchecked")
960         Entry<K,V> e = (Entry<K,V>)tab[index];
961         for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
962             if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {
963                 if (prev != null) {
964                     prev.next = e.next;
965                 } else {
966                     tab[index] = e.next;
967                 }
968                 e.value = null// clear for gc
969                 modCount++;
970                 count--;
971                 return true;
972             }
973         }
974         return false;
975     }
976
977     @Override
978     public synchronized boolean replace(K key, V oldValue, V newValue) {
979         Objects.requireNonNull(oldValue);
980         Objects.requireNonNull(newValue);
981         Entry<?,?> tab[] = table;
982         int hash = key.hashCode();
983         int index = (hash & 0x7FFFFFFF) % tab.length;
984         @SuppressWarnings("unchecked")
985         Entry<K,V> e = (Entry<K,V>)tab[index];
986         for (; e != null; e = e.next) {
987             if ((e.hash == hash) && e.key.equals(key)) {
988                 if (e.value.equals(oldValue)) {
989                     e.value = newValue;
990                     return true;
991                 } else {
992                     return false;
993                 }
994             }
995         }
996         return false;
997     }
998
999     @Override
1000     public synchronized V replace(K key, V value) {
1001         Objects.requireNonNull(value);
1002         Entry<?,?> tab[] = table;
1003         int hash = key.hashCode();
1004         int index = (hash & 0x7FFFFFFF) % tab.length;
1005         @SuppressWarnings("unchecked")
1006         Entry<K,V> e = (Entry<K,V>)tab[index];
1007         for (; e != null; e = e.next) {
1008             if ((e.hash == hash) && e.key.equals(key)) {
1009                 V oldValue = e.value;
1010                 e.value = value;
1011                 return oldValue;
1012             }
1013         }
1014         return null;
1015     }
1016
1017     /**
1018      * {@inheritDoc}
1019      *
1020      * <p>This method will, on a best-effort basis, throw a
1021      * {@link java.util.ConcurrentModificationException} if the mapping
1022      * function modified this map during computation.
1023      *
1024      * @throws ConcurrentModificationException if it is detected that the
1025      * mapping function modified this map
1026      */

1027     @Override
1028     public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
1029         Objects.requireNonNull(mappingFunction);
1030
1031         Entry<?,?> tab[] = table;
1032         int hash = key.hashCode();
1033         int index = (hash & 0x7FFFFFFF) % tab.length;
1034         @SuppressWarnings("unchecked")
1035         Entry<K,V> e = (Entry<K,V>)tab[index];
1036         for (; e != null; e = e.next) {
1037             if (e.hash == hash && e.key.equals(key)) {
1038                 // Hashtable not accept null value
1039                 return e.value;
1040             }
1041         }
1042
1043         int mc = modCount;
1044         V newValue = mappingFunction.apply(key);
1045         if (mc != modCount) { throw new ConcurrentModificationException(); }
1046         if (newValue != null) {
1047             addEntry(hash, key, newValue, index);
1048         }
1049
1050         return newValue;
1051     }
1052
1053     /**
1054      * {@inheritDoc}
1055      *
1056      * <p>This method will, on a best-effort basis, throw a
1057      * {@link java.util.ConcurrentModificationException} if the remapping
1058      * function modified this map during computation.
1059      *
1060      * @throws ConcurrentModificationException if it is detected that the
1061      * remapping function modified this map
1062      */

1063     @Override
1064     public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
1065         Objects.requireNonNull(remappingFunction);
1066
1067         Entry<?,?> tab[] = table;
1068         int hash = key.hashCode();
1069         int index = (hash & 0x7FFFFFFF) % tab.length;
1070         @SuppressWarnings("unchecked")
1071         Entry<K,V> e = (Entry<K,V>)tab[index];
1072         for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1073             if (e.hash == hash && e.key.equals(key)) {
1074                 int mc = modCount;
1075                 V newValue = remappingFunction.apply(key, e.value);
1076                 if (mc != modCount) {
1077                     throw new ConcurrentModificationException();
1078                 }
1079                 if (newValue == null) {
1080                     if (prev != null) {
1081                         prev.next = e.next;
1082                     } else {
1083                         tab[index] = e.next;
1084                     }
1085                     modCount = mc + 1;
1086                     count--;
1087                 } else {
1088                     e.value = newValue;
1089                 }
1090                 return newValue;
1091             }
1092         }
1093         return null;
1094     }
1095     /**
1096      * {@inheritDoc}
1097      *
1098      * <p>This method will, on a best-effort basis, throw a
1099      * {@link java.util.ConcurrentModificationException} if the remapping
1100      * function modified this map during computation.
1101      *
1102      * @throws ConcurrentModificationException if it is detected that the
1103      * remapping function modified this map
1104      */

1105     @Override
1106     public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
1107         Objects.requireNonNull(remappingFunction);
1108
1109         Entry<?,?> tab[] = table;
1110         int hash = key.hashCode();
1111         int index = (hash & 0x7FFFFFFF) % tab.length;
1112         @SuppressWarnings("unchecked")
1113         Entry<K,V> e = (Entry<K,V>)tab[index];
1114         for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1115             if (e.hash == hash && Objects.equals(e.key, key)) {
1116                 int mc = modCount;
1117                 V newValue = remappingFunction.apply(key, e.value);
1118                 if (mc != modCount) {
1119                     throw new ConcurrentModificationException();
1120                 }
1121                 if (newValue == null) {
1122                     if (prev != null) {
1123                         prev.next = e.next;
1124                     } else {
1125                         tab[index] = e.next;
1126                     }
1127                     modCount = mc + 1;
1128                     count--;
1129                 } else {
1130                     e.value = newValue;
1131                 }
1132                 return newValue;
1133             }
1134         }
1135
1136         int mc = modCount;
1137         V newValue = remappingFunction.apply(key, null);
1138         if (mc != modCount) { throw new ConcurrentModificationException(); }
1139         if (newValue != null) {
1140             addEntry(hash, key, newValue, index);
1141         }
1142
1143         return newValue;
1144     }
1145
1146     /**
1147      * {@inheritDoc}
1148      *
1149      * <p>This method will, on a best-effort basis, throw a
1150      * {@link java.util.ConcurrentModificationException} if the remapping
1151      * function modified this map during computation.
1152      *
1153      * @throws ConcurrentModificationException if it is detected that the
1154      * remapping function modified this map
1155      */

1156     @Override
1157     public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
1158         Objects.requireNonNull(remappingFunction);
1159
1160         Entry<?,?> tab[] = table;
1161         int hash = key.hashCode();
1162         int index = (hash & 0x7FFFFFFF) % tab.length;
1163         @SuppressWarnings("unchecked")
1164         Entry<K,V> e = (Entry<K,V>)tab[index];
1165         for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1166             if (e.hash == hash && e.key.equals(key)) {
1167                 int mc = modCount;
1168                 V newValue = remappingFunction.apply(e.value, value);
1169                 if (mc != modCount) {
1170                     throw new ConcurrentModificationException();
1171                 }
1172                 if (newValue == null) {
1173                     if (prev != null) {
1174                         prev.next = e.next;
1175                     } else {
1176                         tab[index] = e.next;
1177                     }
1178                     modCount = mc + 1;
1179                     count--;
1180                 } else {
1181                     e.value = newValue;
1182                 }
1183                 return newValue;
1184             }
1185         }
1186
1187         if (value != null) {
1188             addEntry(hash, key, value, index);
1189         }
1190
1191         return value;
1192     }
1193
1194     /**
1195      * Save the state of the Hashtable to a stream (i.e., serialize it).
1196      *
1197      * @serialData The <i>capacity</i> of the Hashtable (the length of the
1198      *             bucket array) is emitted (int), followed by the
1199      *             <i>size</i> of the Hashtable (the number of key-value
1200      *             mappings), followed by the key (Object) and value (Object)
1201      *             for each key-value mapping represented by the Hashtable
1202      *             The key-value mappings are emitted in no particular order.
1203      */

1204     private void writeObject(java.io.ObjectOutputStream s)
1205             throws IOException {
1206         writeHashtable(s);
1207     }
1208
1209     /**
1210      * Perform serialization of the Hashtable to an ObjectOutputStream.
1211      * The Properties class overrides this method.
1212      */

1213     void writeHashtable(java.io.ObjectOutputStream s)
1214             throws IOException {
1215         Entry<Object, Object> entryStack = null;
1216
1217         synchronized (this) {
1218             // Write out the threshold and loadFactor
1219             s.defaultWriteObject();
1220
1221             // Write out the length and count of elements
1222             s.writeInt(table.length);
1223             s.writeInt(count);
1224
1225             // Stack copies of the entries in the table
1226             for (Entry<?, ?> entry : table) {
1227
1228                 while (entry != null) {
1229                     entryStack =
1230                         new Entry<>(0, entry.key, entry.value, entryStack);
1231                     entry = entry.next;
1232                 }
1233             }
1234         }
1235
1236         // Write out the key/value objects from the stacked entries
1237         while (entryStack != null) {
1238             s.writeObject(entryStack.key);
1239             s.writeObject(entryStack.value);
1240             entryStack = entryStack.next;
1241         }
1242     }
1243
1244     /**
1245      * Called by Properties to write out a simulated threshold and loadfactor.
1246      */

1247     final void defaultWriteHashtable(java.io.ObjectOutputStream s, int length,
1248             float loadFactor) throws IOException {
1249         this.threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
1250         this.loadFactor = loadFactor;
1251         s.defaultWriteObject();
1252     }
1253
1254     /**
1255      * Reconstitute the Hashtable from a stream (i.e., deserialize it).
1256      */

1257     private void readObject(java.io.ObjectInputStream s)
1258             throws IOException, ClassNotFoundException {
1259         readHashtable(s);
1260     }
1261
1262     /**
1263      * Perform deserialization of the Hashtable from an ObjectInputStream.
1264      * The Properties class overrides this method.
1265      */

1266     void readHashtable(java.io.ObjectInputStream s)
1267             throws IOException, ClassNotFoundException {
1268         // Read in the threshold and loadFactor
1269         s.defaultReadObject();
1270
1271         // Validate loadFactor (ignore threshold - it will be re-computed)
1272         if (loadFactor <= 0 || Float.isNaN(loadFactor))
1273             throw new StreamCorruptedException("Illegal Load: " + loadFactor);
1274
1275         // Read the original length of the array and number of elements
1276         int origlength = s.readInt();
1277         int elements = s.readInt();
1278
1279         // Validate # of elements
1280         if (elements < 0)
1281             throw new StreamCorruptedException("Illegal # of Elements: " + elements);
1282
1283         // Clamp original length to be more than elements / loadFactor
1284         // (this is the invariant enforced with auto-growth)
1285         origlength = Math.max(origlength, (int)(elements / loadFactor) + 1);
1286
1287         // Compute new length with a bit of room 5% + 3 to grow but
1288         // no larger than the clamped original length.  Make the length
1289         // odd if it's large enough, this helps distribute the entries.
1290         // Guard against the length ending up zero, that's not valid.
1291         int length = (int)((elements + elements / 20) / loadFactor) + 3;
1292         if (length > elements && (length & 1) == 0)
1293             length--;
1294         length = Math.min(length, origlength);
1295
1296         if (length < 0) { // overflow
1297             length = origlength;
1298         }
1299
1300         // Check Map.Entry[].class since it's the nearest public type to
1301         // what we're actually creating.
1302         SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, length);
1303         table = new Entry<?,?>[length];
1304         threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
1305         count = 0;
1306
1307         // Read the number of elements and then all the key/value objects
1308         for (; elements > 0; elements--) {
1309             @SuppressWarnings("unchecked")
1310                 K key = (K)s.readObject();
1311             @SuppressWarnings("unchecked")
1312                 V value = (V)s.readObject();
1313             // sync is eliminated for performance
1314             reconstitutionPut(table, key, value);
1315         }
1316     }
1317
1318     /**
1319      * The put method used by readObject. This is provided because put
1320      * is overridable and should not be called in readObject since the
1321      * subclass will not yet be initialized.
1322      *
1323      * <p>This differs from the regular put method in several ways. No
1324      * checking for rehashing is necessary since the number of elements
1325      * initially in the table is known. The modCount is not incremented and
1326      * there's no synchronization because we are creating a new instance.
1327      * Also, no return value is needed.
1328      */

1329     private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
1330         throws StreamCorruptedException
1331     {
1332         if (value == null) {
1333             throw new java.io.StreamCorruptedException();
1334         }
1335         // Makes sure the key is not already in the hashtable.
1336         // This should not happen in deserialized version.
1337         int hash = key.hashCode();
1338         int index = (hash & 0x7FFFFFFF) % tab.length;
1339         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
1340             if ((e.hash == hash) && e.key.equals(key)) {
1341                 throw new java.io.StreamCorruptedException();
1342             }
1343         }
1344         // Creates the new entry.
1345         @SuppressWarnings("unchecked")
1346             Entry<K,V> e = (Entry<K,V>)tab[index];
1347         tab[index] = new Entry<>(hash, key, value, e);
1348         count++;
1349     }
1350
1351     /**
1352      * Hashtable bucket collision list entry
1353      */

1354     private static class Entry<K,V> implements Map.Entry<K,V> {
1355         final int hash;
1356         final K key;
1357         V value;
1358         Entry<K,V> next;
1359
1360         protected Entry(int hash, K key, V value, Entry<K,V> next) {
1361             this.hash = hash;
1362             this.key =  key;
1363             this.value = value;
1364             this.next = next;
1365         }
1366
1367         @SuppressWarnings("unchecked")
1368         protected Object clone() {
1369             return new Entry<>(hash, key, value,
1370                                   (next==null ? null : (Entry<K,V>) next.clone()));
1371         }
1372
1373         // Map.Entry Ops
1374
1375         public K getKey() {
1376             return key;
1377         }
1378
1379         public V getValue() {
1380             return value;
1381         }
1382
1383         public V setValue(V value) {
1384             if (value == null)
1385                 throw new NullPointerException();
1386
1387             V oldValue = this.value;
1388             this.value = value;
1389             return oldValue;
1390         }
1391
1392         public boolean equals(Object o) {
1393             if (!(o instanceof Map.Entry))
1394                 return false;
1395             Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1396
1397             return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
1398                (value==null ? e.getValue()==null : value.equals(e.getValue()));
1399         }
1400
1401         public int hashCode() {
1402             return hash ^ Objects.hashCode(value);
1403         }
1404
1405         public String toString() {
1406             return key.toString()+"="+value.toString();
1407         }
1408     }
1409
1410     // Types of Enumerations/Iterations
1411     private static final int KEYS = 0;
1412     private static final int VALUES = 1;
1413     private static final int ENTRIES = 2;
1414
1415     /**
1416      * A hashtable enumerator class.  This class implements both the
1417      * Enumeration and Iterator interfaces, but individual instances
1418      * can be created with the Iterator methods disabled.  This is necessary
1419      * to avoid unintentionally increasing the capabilities granted a user
1420      * by passing an Enumeration.
1421      */

1422     private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
1423         final Entry<?,?>[] table = Hashtable.this.table;
1424         int index = table.length;
1425         Entry<?,?> entry;
1426         Entry<?,?> lastReturned;
1427         final int type;
1428
1429         /**
1430          * Indicates whether this Enumerator is serving as an Iterator
1431          * or an Enumeration.  (true -> Iterator).
1432          */

1433         final boolean iterator;
1434
1435         /**
1436          * The modCount value that the iterator believes that the backing
1437          * Hashtable should have.  If this expectation is violated, the iterator
1438          * has detected concurrent modification.
1439          */

1440         protected int expectedModCount = Hashtable.this.modCount;
1441
1442         Enumerator(int type, boolean iterator) {
1443             this.type = type;
1444             this.iterator = iterator;
1445         }
1446
1447         public boolean hasMoreElements() {
1448             Entry<?,?> e = entry;
1449             int i = index;
1450             Entry<?,?>[] t = table;
1451             /* Use locals for faster loop iteration */
1452             while (e == null && i > 0) {
1453                 e = t[--i];
1454             }
1455             entry = e;
1456             index = i;
1457             return e != null;
1458         }
1459
1460         @SuppressWarnings("unchecked")
1461         public T nextElement() {
1462             Entry<?,?> et = entry;
1463             int i = index;
1464             Entry<?,?>[] t = table;
1465             /* Use locals for faster loop iteration */
1466             while (et == null && i > 0) {
1467                 et = t[--i];
1468             }
1469             entry = et;
1470             index = i;
1471             if (et != null) {
1472                 Entry<?,?> e = lastReturned = entry;
1473                 entry = e.next;
1474                 return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
1475             }
1476             throw new NoSuchElementException("Hashtable Enumerator");
1477         }
1478
1479         // Iterator methods
1480         public boolean hasNext() {
1481             return hasMoreElements();
1482         }
1483
1484         public T next() {
1485             if (Hashtable.this.modCount != expectedModCount)
1486                 throw new ConcurrentModificationException();
1487             return nextElement();
1488         }
1489
1490         public void remove() {
1491             if (!iterator)
1492                 throw new UnsupportedOperationException();
1493             if (lastReturned == null)
1494                 throw new IllegalStateException("Hashtable Enumerator");
1495             if (modCount != expectedModCount)
1496                 throw new ConcurrentModificationException();
1497
1498             synchronized(Hashtable.this) {
1499                 Entry<?,?>[] tab = Hashtable.this.table;
1500                 int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
1501
1502                 @SuppressWarnings("unchecked")
1503                 Entry<K,V> e = (Entry<K,V>)tab[index];
1504                 for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1505                     if (e == lastReturned) {
1506                         if (prev == null)
1507                             tab[index] = e.next;
1508                         else
1509                             prev.next = e.next;
1510                         expectedModCount++;
1511                         lastReturned = null;
1512                         Hashtable.this.modCount++;
1513                         Hashtable.this.count--;
1514                         return;
1515                     }
1516                 }
1517                 throw new ConcurrentModificationException();
1518             }
1519         }
1520     }
1521 }
1522