1 /*
2  * Copyright (c) 1994, 2019, 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.access.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     @java.io.Serial
175     private static final long serialVersionUID = 1421746759512286392L;
176 
177     /**
178      * Constructs a new, empty hashtable with the specified initial
179      * capacity and the specified load factor.
180      *
181      * @param      initialCapacity   the initial capacity of the hashtable.
182      * @param      loadFactor        the load factor of the hashtable.
183      * @throws     IllegalArgumentException  if the initial capacity is less
184      *             than zero, or if the load factor is nonpositive.
185      */
Hashtable(int initialCapacity, float loadFactor)186     public Hashtable(int initialCapacity, float loadFactor) {
187         if (initialCapacity < 0)
188             throw new IllegalArgumentException("Illegal Capacity: "+
189                                                initialCapacity);
190         if (loadFactor <= 0 || Float.isNaN(loadFactor))
191             throw new IllegalArgumentException("Illegal Load: "+loadFactor);
192 
193         if (initialCapacity==0)
194             initialCapacity = 1;
195         this.loadFactor = loadFactor;
196         table = new Entry<?,?>[initialCapacity];
197         threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
198     }
199 
200     /**
201      * Constructs a new, empty hashtable with the specified initial capacity
202      * and default load factor (0.75).
203      *
204      * @param     initialCapacity   the initial capacity of the hashtable.
205      * @throws    IllegalArgumentException if the initial capacity is less
206      *              than zero.
207      */
Hashtable(int initialCapacity)208     public Hashtable(int initialCapacity) {
209         this(initialCapacity, 0.75f);
210     }
211 
212     /**
213      * Constructs a new, empty hashtable with a default initial capacity (11)
214      * and load factor (0.75).
215      */
Hashtable()216     public Hashtable() {
217         this(11, 0.75f);
218     }
219 
220     /**
221      * Constructs a new hashtable with the same mappings as the given
222      * Map.  The hashtable is created with an initial capacity sufficient to
223      * hold the mappings in the given Map and a default load factor (0.75).
224      *
225      * @param t the map whose mappings are to be placed in this map.
226      * @throws NullPointerException if the specified map is null.
227      * @since   1.2
228      */
Hashtable(Map<? extends K, ? extends V> t)229     public Hashtable(Map<? extends K, ? extends V> t) {
230         this(Math.max(2*t.size(), 11), 0.75f);
231         putAll(t);
232     }
233 
234     /**
235      * A constructor chained from {@link Properties} keeps Hashtable fields
236      * uninitialized since they are not used.
237      *
238      * @param dummy a dummy parameter
239      */
Hashtable(Void dummy)240     Hashtable(Void dummy) {}
241 
242     /**
243      * Returns the number of keys in this hashtable.
244      *
245      * @return  the number of keys in this hashtable.
246      */
size()247     public synchronized int size() {
248         return count;
249     }
250 
251     /**
252      * Tests if this hashtable maps no keys to values.
253      *
254      * @return  {@code true} if this hashtable maps no keys to values;
255      *          {@code false} otherwise.
256      */
isEmpty()257     public synchronized boolean isEmpty() {
258         return count == 0;
259     }
260 
261     /**
262      * Returns an enumeration of the keys in this hashtable.
263      * Use the Enumeration methods on the returned object to fetch the keys
264      * sequentially. If the hashtable is structurally modified while enumerating
265      * over the keys then the results of enumerating are undefined.
266      *
267      * @return  an enumeration of the keys in this hashtable.
268      * @see     Enumeration
269      * @see     #elements()
270      * @see     #keySet()
271      * @see     Map
272      */
keys()273     public synchronized Enumeration<K> keys() {
274         return this.<K>getEnumeration(KEYS);
275     }
276 
277     /**
278      * Returns an enumeration of the values in this hashtable.
279      * Use the Enumeration methods on the returned object to fetch the elements
280      * sequentially. If the hashtable is structurally modified while enumerating
281      * over the values then the results of enumerating are undefined.
282      *
283      * @return  an enumeration of the values in this hashtable.
284      * @see     java.util.Enumeration
285      * @see     #keys()
286      * @see     #values()
287      * @see     Map
288      */
elements()289     public synchronized Enumeration<V> elements() {
290         return this.<V>getEnumeration(VALUES);
291     }
292 
293     /**
294      * Tests if some key maps into the specified value in this hashtable.
295      * This operation is more expensive than the {@link #containsKey
296      * containsKey} method.
297      *
298      * <p>Note that this method is identical in functionality to
299      * {@link #containsValue containsValue}, (which is part of the
300      * {@link Map} interface in the collections framework).
301      *
302      * @param      value   a value to search for
303      * @return     {@code true} if and only if some key maps to the
304      *             {@code value} argument in this hashtable as
305      *             determined by the {@code equals} method;
306      *             {@code false} otherwise.
307      * @throws     NullPointerException  if the value is {@code null}
308      */
contains(Object value)309     public synchronized boolean contains(Object value) {
310         if (value == null) {
311             throw new NullPointerException();
312         }
313 
314         Entry<?,?> tab[] = table;
315         for (int i = tab.length ; i-- > 0 ;) {
316             for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
317                 if (e.value.equals(value)) {
318                     return true;
319                 }
320             }
321         }
322         return false;
323     }
324 
325     /**
326      * Returns true if this hashtable maps one or more keys to this value.
327      *
328      * <p>Note that this method is identical in functionality to {@link
329      * #contains contains} (which predates the {@link Map} interface).
330      *
331      * @param value value whose presence in this hashtable is to be tested
332      * @return {@code true} if this map maps one or more keys to the
333      *         specified value
334      * @throws NullPointerException  if the value is {@code null}
335      * @since 1.2
336      */
containsValue(Object value)337     public boolean containsValue(Object value) {
338         return contains(value);
339     }
340 
341     /**
342      * Tests if the specified object is a key in this hashtable.
343      *
344      * @param   key   possible key
345      * @return  {@code true} if and only if the specified object
346      *          is a key in this hashtable, as determined by the
347      *          {@code equals} method; {@code false} otherwise.
348      * @throws  NullPointerException  if the key is {@code null}
349      * @see     #contains(Object)
350      */
containsKey(Object key)351     public synchronized boolean containsKey(Object key) {
352         Entry<?,?> tab[] = table;
353         int hash = key.hashCode();
354         int index = (hash & 0x7FFFFFFF) % tab.length;
355         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
356             if ((e.hash == hash) && e.key.equals(key)) {
357                 return true;
358             }
359         }
360         return false;
361     }
362 
363     /**
364      * Returns the value to which the specified key is mapped,
365      * or {@code null} if this map contains no mapping for the key.
366      *
367      * <p>More formally, if this map contains a mapping from a key
368      * {@code k} to a value {@code v} such that {@code (key.equals(k))},
369      * then this method returns {@code v}; otherwise it returns
370      * {@code null}.  (There can be at most one such mapping.)
371      *
372      * @param key the key whose associated value is to be returned
373      * @return the value to which the specified key is mapped, or
374      *         {@code null} if this map contains no mapping for the key
375      * @throws NullPointerException if the specified key is null
376      * @see     #put(Object, Object)
377      */
378     @SuppressWarnings("unchecked")
get(Object key)379     public synchronized V get(Object key) {
380         Entry<?,?> tab[] = table;
381         int hash = key.hashCode();
382         int index = (hash & 0x7FFFFFFF) % tab.length;
383         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
384             if ((e.hash == hash) && e.key.equals(key)) {
385                 return (V)e.value;
386             }
387         }
388         return null;
389     }
390 
391     /**
392      * The maximum size of array to allocate.
393      * Some VMs reserve some header words in an array.
394      * Attempts to allocate larger arrays may result in
395      * OutOfMemoryError: Requested array size exceeds VM limit
396      */
397     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
398 
399     /**
400      * Increases the capacity of and internally reorganizes this
401      * hashtable, in order to accommodate and access its entries more
402      * efficiently.  This method is called automatically when the
403      * number of keys in the hashtable exceeds this hashtable's capacity
404      * and load factor.
405      */
406     @SuppressWarnings("unchecked")
rehash()407     protected void rehash() {
408         int oldCapacity = table.length;
409         Entry<?,?>[] oldMap = table;
410 
411         // overflow-conscious code
412         int newCapacity = (oldCapacity << 1) + 1;
413         if (newCapacity - MAX_ARRAY_SIZE > 0) {
414             if (oldCapacity == MAX_ARRAY_SIZE)
415                 // Keep running with MAX_ARRAY_SIZE buckets
416                 return;
417             newCapacity = MAX_ARRAY_SIZE;
418         }
419         Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
420 
421         modCount++;
422         threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
423         table = newMap;
424 
425         for (int i = oldCapacity ; i-- > 0 ;) {
426             for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
427                 Entry<K,V> e = old;
428                 old = old.next;
429 
430                 int index = (e.hash & 0x7FFFFFFF) % newCapacity;
431                 e.next = (Entry<K,V>)newMap[index];
432                 newMap[index] = e;
433             }
434         }
435     }
436 
addEntry(int hash, K key, V value, int index)437     private void addEntry(int hash, K key, V value, int index) {
438         Entry<?,?> tab[] = table;
439         if (count >= threshold) {
440             // Rehash the table if the threshold is exceeded
441             rehash();
442 
443             tab = table;
444             hash = key.hashCode();
445             index = (hash & 0x7FFFFFFF) % tab.length;
446         }
447 
448         // Creates the new entry.
449         @SuppressWarnings("unchecked")
450         Entry<K,V> e = (Entry<K,V>) tab[index];
451         tab[index] = new Entry<>(hash, key, value, e);
452         count++;
453         modCount++;
454     }
455 
456     /**
457      * Maps the specified {@code key} to the specified
458      * {@code value} in this hashtable. Neither the key nor the
459      * value can be {@code null}. <p>
460      *
461      * The value can be retrieved by calling the {@code get} method
462      * with a key that is equal to the original key.
463      *
464      * @param      key     the hashtable key
465      * @param      value   the value
466      * @return     the previous value of the specified key in this hashtable,
467      *             or {@code null} if it did not have one
468      * @throws     NullPointerException  if the key or value is
469      *               {@code null}
470      * @see     Object#equals(Object)
471      * @see     #get(Object)
472      */
put(K key, V value)473     public synchronized V put(K key, V value) {
474         // Make sure the value is not null
475         if (value == null) {
476             throw new NullPointerException();
477         }
478 
479         // Makes sure the key is not already in the hashtable.
480         Entry<?,?> tab[] = table;
481         int hash = key.hashCode();
482         int index = (hash & 0x7FFFFFFF) % tab.length;
483         @SuppressWarnings("unchecked")
484         Entry<K,V> entry = (Entry<K,V>)tab[index];
485         for(; entry != null ; entry = entry.next) {
486             if ((entry.hash == hash) && entry.key.equals(key)) {
487                 V old = entry.value;
488                 entry.value = value;
489                 return old;
490             }
491         }
492 
493         addEntry(hash, key, value, index);
494         return null;
495     }
496 
497     /**
498      * Removes the key (and its corresponding value) from this
499      * hashtable. This method does nothing if the key is not in the hashtable.
500      *
501      * @param   key   the key that needs to be removed
502      * @return  the value to which the key had been mapped in this hashtable,
503      *          or {@code null} if the key did not have a mapping
504      * @throws  NullPointerException  if the key is {@code null}
505      */
remove(Object key)506     public synchronized V remove(Object key) {
507         Entry<?,?> tab[] = table;
508         int hash = key.hashCode();
509         int index = (hash & 0x7FFFFFFF) % tab.length;
510         @SuppressWarnings("unchecked")
511         Entry<K,V> e = (Entry<K,V>)tab[index];
512         for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
513             if ((e.hash == hash) && e.key.equals(key)) {
514                 if (prev != null) {
515                     prev.next = e.next;
516                 } else {
517                     tab[index] = e.next;
518                 }
519                 modCount++;
520                 count--;
521                 V oldValue = e.value;
522                 e.value = null;
523                 return oldValue;
524             }
525         }
526         return null;
527     }
528 
529     /**
530      * Copies all of the mappings from the specified map to this hashtable.
531      * These mappings will replace any mappings that this hashtable had for any
532      * of the keys currently in the specified map.
533      *
534      * @param t mappings to be stored in this map
535      * @throws NullPointerException if the specified map is null
536      * @since 1.2
537      */
putAll(Map<? extends K, ? extends V> t)538     public synchronized void putAll(Map<? extends K, ? extends V> t) {
539         for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
540             put(e.getKey(), e.getValue());
541     }
542 
543     /**
544      * Clears this hashtable so that it contains no keys.
545      */
clear()546     public synchronized void clear() {
547         Entry<?,?> tab[] = table;
548         for (int index = tab.length; --index >= 0; )
549             tab[index] = null;
550         modCount++;
551         count = 0;
552     }
553 
554     /**
555      * Creates a shallow copy of this hashtable. All the structure of the
556      * hashtable itself is copied, but the keys and values are not cloned.
557      * This is a relatively expensive operation.
558      *
559      * @return  a clone of the hashtable
560      */
clone()561     public synchronized Object clone() {
562         Hashtable<?,?> t = cloneHashtable();
563         t.table = new Entry<?,?>[table.length];
564         for (int i = table.length ; i-- > 0 ; ) {
565             t.table[i] = (table[i] != null)
566                 ? (Entry<?,?>) table[i].clone() : null;
567         }
568         t.keySet = null;
569         t.entrySet = null;
570         t.values = null;
571         t.modCount = 0;
572         return t;
573     }
574 
575     /** Calls super.clone() */
cloneHashtable()576     final Hashtable<?,?> cloneHashtable() {
577         try {
578             return (Hashtable<?,?>)super.clone();
579         } catch (CloneNotSupportedException e) {
580             // this shouldn't happen, since we are Cloneable
581             throw new InternalError(e);
582         }
583     }
584 
585     /**
586      * Returns a string representation of this {@code Hashtable} object
587      * in the form of a set of entries, enclosed in braces and separated
588      * by the ASCII characters "<code> ,&nbsp;</code>" (comma and space). Each
589      * entry is rendered as the key, an equals sign {@code =}, and the
590      * associated element, where the {@code toString} method is used to
591      * convert the key and element to strings.
592      *
593      * @return  a string representation of this hashtable
594      */
toString()595     public synchronized String toString() {
596         int max = size() - 1;
597         if (max == -1)
598             return "{}";
599 
600         StringBuilder sb = new StringBuilder();
601         Iterator<Map.Entry<K,V>> it = entrySet().iterator();
602 
603         sb.append('{');
604         for (int i = 0; ; i++) {
605             Map.Entry<K,V> e = it.next();
606             K key = e.getKey();
607             V value = e.getValue();
608             sb.append(key   == this ? "(this Map)" : key.toString());
609             sb.append('=');
610             sb.append(value == this ? "(this Map)" : value.toString());
611 
612             if (i == max)
613                 return sb.append('}').toString();
614             sb.append(", ");
615         }
616     }
617 
618 
getEnumeration(int type)619     private <T> Enumeration<T> getEnumeration(int type) {
620         if (count == 0) {
621             return Collections.emptyEnumeration();
622         } else {
623             return new Enumerator<>(type, false);
624         }
625     }
626 
getIterator(int type)627     private <T> Iterator<T> getIterator(int type) {
628         if (count == 0) {
629             return Collections.emptyIterator();
630         } else {
631             return new Enumerator<>(type, true);
632         }
633     }
634 
635     // Views
636 
637     /**
638      * Each of these fields are initialized to contain an instance of the
639      * appropriate view the first time this view is requested.  The views are
640      * stateless, so there's no reason to create more than one of each.
641      */
642     private transient volatile Set<K> keySet;
643     private transient volatile Set<Map.Entry<K,V>> entrySet;
644     private transient volatile Collection<V> values;
645 
646     /**
647      * Returns a {@link Set} view of the keys contained in this map.
648      * The set is backed by the map, so changes to the map are
649      * reflected in the set, and vice-versa.  If the map is modified
650      * while an iteration over the set is in progress (except through
651      * the iterator's own {@code remove} operation), the results of
652      * the iteration are undefined.  The set supports element removal,
653      * which removes the corresponding mapping from the map, via the
654      * {@code Iterator.remove}, {@code Set.remove},
655      * {@code removeAll}, {@code retainAll}, and {@code clear}
656      * operations.  It does not support the {@code add} or {@code addAll}
657      * operations.
658      *
659      * @since 1.2
660      */
keySet()661     public Set<K> keySet() {
662         if (keySet == null)
663             keySet = Collections.synchronizedSet(new KeySet(), this);
664         return keySet;
665     }
666 
667     private class KeySet extends AbstractSet<K> {
iterator()668         public Iterator<K> iterator() {
669             return getIterator(KEYS);
670         }
size()671         public int size() {
672             return count;
673         }
contains(Object o)674         public boolean contains(Object o) {
675             return containsKey(o);
676         }
remove(Object o)677         public boolean remove(Object o) {
678             return Hashtable.this.remove(o) != null;
679         }
clear()680         public void clear() {
681             Hashtable.this.clear();
682         }
683     }
684 
685     /**
686      * Returns a {@link Set} view of the mappings contained in this map.
687      * The set is backed by the map, so changes to the map are
688      * reflected in the set, and vice-versa.  If the map is modified
689      * while an iteration over the set is in progress (except through
690      * the iterator's own {@code remove} operation, or through the
691      * {@code setValue} operation on a map entry returned by the
692      * iterator) the results of the iteration are undefined.  The set
693      * supports element removal, which removes the corresponding
694      * mapping from the map, via the {@code Iterator.remove},
695      * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
696      * {@code clear} operations.  It does not support the
697      * {@code add} or {@code addAll} operations.
698      *
699      * @since 1.2
700      */
entrySet()701     public Set<Map.Entry<K,V>> entrySet() {
702         if (entrySet==null)
703             entrySet = Collections.synchronizedSet(new EntrySet(), this);
704         return entrySet;
705     }
706 
707     private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
iterator()708         public Iterator<Map.Entry<K,V>> iterator() {
709             return getIterator(ENTRIES);
710         }
711 
add(Map.Entry<K,V> o)712         public boolean add(Map.Entry<K,V> o) {
713             return super.add(o);
714         }
715 
contains(Object o)716         public boolean contains(Object o) {
717             if (!(o instanceof Map.Entry))
718                 return false;
719             Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
720             Object key = entry.getKey();
721             Entry<?,?>[] tab = table;
722             int hash = key.hashCode();
723             int index = (hash & 0x7FFFFFFF) % tab.length;
724 
725             for (Entry<?,?> e = tab[index]; e != null; e = e.next)
726                 if (e.hash==hash && e.equals(entry))
727                     return true;
728             return false;
729         }
730 
remove(Object o)731         public boolean remove(Object o) {
732             if (!(o instanceof Map.Entry))
733                 return false;
734             Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
735             Object key = entry.getKey();
736             Entry<?,?>[] tab = table;
737             int hash = key.hashCode();
738             int index = (hash & 0x7FFFFFFF) % tab.length;
739 
740             @SuppressWarnings("unchecked")
741             Entry<K,V> e = (Entry<K,V>)tab[index];
742             for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
743                 if (e.hash==hash && e.equals(entry)) {
744                     if (prev != null)
745                         prev.next = e.next;
746                     else
747                         tab[index] = e.next;
748 
749                     e.value = null; // clear for gc.
750                     modCount++;
751                     count--;
752                     return true;
753                 }
754             }
755             return false;
756         }
757 
size()758         public int size() {
759             return count;
760         }
761 
clear()762         public void clear() {
763             Hashtable.this.clear();
764         }
765     }
766 
767     /**
768      * Returns a {@link Collection} view of the values contained in this map.
769      * The collection is backed by the map, so changes to the map are
770      * reflected in the collection, and vice-versa.  If the map is
771      * modified while an iteration over the collection is in progress
772      * (except through the iterator's own {@code remove} operation),
773      * the results of the iteration are undefined.  The collection
774      * supports element removal, which removes the corresponding
775      * mapping from the map, via the {@code Iterator.remove},
776      * {@code Collection.remove}, {@code removeAll},
777      * {@code retainAll} and {@code clear} operations.  It does not
778      * support the {@code add} or {@code addAll} operations.
779      *
780      * @since 1.2
781      */
values()782     public Collection<V> values() {
783         if (values==null)
784             values = Collections.synchronizedCollection(new ValueCollection(),
785                                                         this);
786         return values;
787     }
788 
789     private class ValueCollection extends AbstractCollection<V> {
iterator()790         public Iterator<V> iterator() {
791             return getIterator(VALUES);
792         }
size()793         public int size() {
794             return count;
795         }
contains(Object o)796         public boolean contains(Object o) {
797             return containsValue(o);
798         }
clear()799         public void clear() {
800             Hashtable.this.clear();
801         }
802     }
803 
804     // Comparison and hashing
805 
806     /**
807      * Compares the specified Object with this Map for equality,
808      * as per the definition in the Map interface.
809      *
810      * @param  o object to be compared for equality with this hashtable
811      * @return true if the specified Object is equal to this Map
812      * @see Map#equals(Object)
813      * @since 1.2
814      */
equals(Object o)815     public synchronized boolean equals(Object o) {
816         if (o == this)
817             return true;
818 
819         if (!(o instanceof Map))
820             return false;
821         Map<?,?> t = (Map<?,?>) o;
822         if (t.size() != size())
823             return false;
824 
825         try {
826             for (Map.Entry<K, V> e : entrySet()) {
827                 K key = e.getKey();
828                 V value = e.getValue();
829                 if (value == null) {
830                     if (!(t.get(key) == null && t.containsKey(key)))
831                         return false;
832                 } else {
833                     if (!value.equals(t.get(key)))
834                         return false;
835                 }
836             }
837         } catch (ClassCastException unused)   {
838             return false;
839         } catch (NullPointerException unused) {
840             return false;
841         }
842 
843         return true;
844     }
845 
846     /**
847      * Returns the hash code value for this Map as per the definition in the
848      * Map interface.
849      *
850      * @see Map#hashCode()
851      * @since 1.2
852      */
hashCode()853     public synchronized int hashCode() {
854         /*
855          * This code detects the recursion caused by computing the hash code
856          * of a self-referential hash table and prevents the stack overflow
857          * that would otherwise result.  This allows certain 1.1-era
858          * applets with self-referential hash tables to work.  This code
859          * abuses the loadFactor field to do double-duty as a hashCode
860          * in progress flag, so as not to worsen the space performance.
861          * A negative load factor indicates that hash code computation is
862          * in progress.
863          */
864         int h = 0;
865         if (count == 0 || loadFactor < 0)
866             return h;  // Returns zero
867 
868         loadFactor = -loadFactor;  // Mark hashCode computation in progress
869         Entry<?,?>[] tab = table;
870         for (Entry<?,?> entry : tab) {
871             while (entry != null) {
872                 h += entry.hashCode();
873                 entry = entry.next;
874             }
875         }
876 
877         loadFactor = -loadFactor;  // Mark hashCode computation complete
878 
879         return h;
880     }
881 
882     @Override
getOrDefault(Object key, V defaultValue)883     public synchronized V getOrDefault(Object key, V defaultValue) {
884         V result = get(key);
885         return (null == result) ? defaultValue : result;
886     }
887 
888     @SuppressWarnings("unchecked")
889     @Override
forEach(BiConsumer<? super K, ? super V> action)890     public synchronized void forEach(BiConsumer<? super K, ? super V> action) {
891         Objects.requireNonNull(action);     // explicit check required in case
892                                             // table is empty.
893         final int expectedModCount = modCount;
894 
895         Entry<?, ?>[] tab = table;
896         for (Entry<?, ?> entry : tab) {
897             while (entry != null) {
898                 action.accept((K)entry.key, (V)entry.value);
899                 entry = entry.next;
900 
901                 if (expectedModCount != modCount) {
902                     throw new ConcurrentModificationException();
903                 }
904             }
905         }
906     }
907 
908     @SuppressWarnings("unchecked")
909     @Override
replaceAll(BiFunction<? super K, ? super V, ? extends V> function)910     public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
911         Objects.requireNonNull(function);     // explicit check required in case
912                                               // table is empty.
913         final int expectedModCount = modCount;
914 
915         Entry<K, V>[] tab = (Entry<K, V>[])table;
916         for (Entry<K, V> entry : tab) {
917             while (entry != null) {
918                 entry.value = Objects.requireNonNull(
919                     function.apply(entry.key, entry.value));
920                 entry = entry.next;
921 
922                 if (expectedModCount != modCount) {
923                     throw new ConcurrentModificationException();
924                 }
925             }
926         }
927     }
928 
929     @Override
putIfAbsent(K key, V value)930     public synchronized V putIfAbsent(K key, V value) {
931         Objects.requireNonNull(value);
932 
933         // Makes sure the key is not already in the hashtable.
934         Entry<?,?> tab[] = table;
935         int hash = key.hashCode();
936         int index = (hash & 0x7FFFFFFF) % tab.length;
937         @SuppressWarnings("unchecked")
938         Entry<K,V> entry = (Entry<K,V>)tab[index];
939         for (; entry != null; entry = entry.next) {
940             if ((entry.hash == hash) && entry.key.equals(key)) {
941                 V old = entry.value;
942                 if (old == null) {
943                     entry.value = value;
944                 }
945                 return old;
946             }
947         }
948 
949         addEntry(hash, key, value, index);
950         return null;
951     }
952 
953     @Override
remove(Object key, Object value)954     public synchronized boolean remove(Object key, Object value) {
955         Objects.requireNonNull(value);
956 
957         Entry<?,?> tab[] = table;
958         int hash = key.hashCode();
959         int index = (hash & 0x7FFFFFFF) % tab.length;
960         @SuppressWarnings("unchecked")
961         Entry<K,V> e = (Entry<K,V>)tab[index];
962         for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
963             if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {
964                 if (prev != null) {
965                     prev.next = e.next;
966                 } else {
967                     tab[index] = e.next;
968                 }
969                 e.value = null; // clear for gc
970                 modCount++;
971                 count--;
972                 return true;
973             }
974         }
975         return false;
976     }
977 
978     @Override
replace(K key, V oldValue, V newValue)979     public synchronized boolean replace(K key, V oldValue, V newValue) {
980         Objects.requireNonNull(oldValue);
981         Objects.requireNonNull(newValue);
982         Entry<?,?> tab[] = table;
983         int hash = key.hashCode();
984         int index = (hash & 0x7FFFFFFF) % tab.length;
985         @SuppressWarnings("unchecked")
986         Entry<K,V> e = (Entry<K,V>)tab[index];
987         for (; e != null; e = e.next) {
988             if ((e.hash == hash) && e.key.equals(key)) {
989                 if (e.value.equals(oldValue)) {
990                     e.value = newValue;
991                     return true;
992                 } else {
993                     return false;
994                 }
995             }
996         }
997         return false;
998     }
999 
1000     @Override
replace(K key, V value)1001     public synchronized V replace(K key, V value) {
1002         Objects.requireNonNull(value);
1003         Entry<?,?> tab[] = table;
1004         int hash = key.hashCode();
1005         int index = (hash & 0x7FFFFFFF) % tab.length;
1006         @SuppressWarnings("unchecked")
1007         Entry<K,V> e = (Entry<K,V>)tab[index];
1008         for (; e != null; e = e.next) {
1009             if ((e.hash == hash) && e.key.equals(key)) {
1010                 V oldValue = e.value;
1011                 e.value = value;
1012                 return oldValue;
1013             }
1014         }
1015         return null;
1016     }
1017 
1018     /**
1019      * {@inheritDoc}
1020      *
1021      * <p>This method will, on a best-effort basis, throw a
1022      * {@link java.util.ConcurrentModificationException} if the mapping
1023      * function modified this map during computation.
1024      *
1025      * @throws ConcurrentModificationException if it is detected that the
1026      * mapping function modified this map
1027      */
1028     @Override
computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)1029     public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
1030         Objects.requireNonNull(mappingFunction);
1031 
1032         Entry<?,?> tab[] = table;
1033         int hash = key.hashCode();
1034         int index = (hash & 0x7FFFFFFF) % tab.length;
1035         @SuppressWarnings("unchecked")
1036         Entry<K,V> e = (Entry<K,V>)tab[index];
1037         for (; e != null; e = e.next) {
1038             if (e.hash == hash && e.key.equals(key)) {
1039                 // Hashtable not accept null value
1040                 return e.value;
1041             }
1042         }
1043 
1044         int mc = modCount;
1045         V newValue = mappingFunction.apply(key);
1046         if (mc != modCount) { throw new ConcurrentModificationException(); }
1047         if (newValue != null) {
1048             addEntry(hash, key, newValue, index);
1049         }
1050 
1051         return newValue;
1052     }
1053 
1054     /**
1055      * {@inheritDoc}
1056      *
1057      * <p>This method will, on a best-effort basis, throw a
1058      * {@link java.util.ConcurrentModificationException} if the remapping
1059      * function modified this map during computation.
1060      *
1061      * @throws ConcurrentModificationException if it is detected that the
1062      * remapping function modified this map
1063      */
1064     @Override
computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)1065     public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
1066         Objects.requireNonNull(remappingFunction);
1067 
1068         Entry<?,?> tab[] = table;
1069         int hash = key.hashCode();
1070         int index = (hash & 0x7FFFFFFF) % tab.length;
1071         @SuppressWarnings("unchecked")
1072         Entry<K,V> e = (Entry<K,V>)tab[index];
1073         for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1074             if (e.hash == hash && e.key.equals(key)) {
1075                 int mc = modCount;
1076                 V newValue = remappingFunction.apply(key, e.value);
1077                 if (mc != modCount) {
1078                     throw new ConcurrentModificationException();
1079                 }
1080                 if (newValue == null) {
1081                     if (prev != null) {
1082                         prev.next = e.next;
1083                     } else {
1084                         tab[index] = e.next;
1085                     }
1086                     modCount = mc + 1;
1087                     count--;
1088                 } else {
1089                     e.value = newValue;
1090                 }
1091                 return newValue;
1092             }
1093         }
1094         return null;
1095     }
1096     /**
1097      * {@inheritDoc}
1098      *
1099      * <p>This method will, on a best-effort basis, throw a
1100      * {@link java.util.ConcurrentModificationException} if the remapping
1101      * function modified this map during computation.
1102      *
1103      * @throws ConcurrentModificationException if it is detected that the
1104      * remapping function modified this map
1105      */
1106     @Override
compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)1107     public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
1108         Objects.requireNonNull(remappingFunction);
1109 
1110         Entry<?,?> tab[] = table;
1111         int hash = key.hashCode();
1112         int index = (hash & 0x7FFFFFFF) % tab.length;
1113         @SuppressWarnings("unchecked")
1114         Entry<K,V> e = (Entry<K,V>)tab[index];
1115         for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1116             if (e.hash == hash && Objects.equals(e.key, key)) {
1117                 int mc = modCount;
1118                 V newValue = remappingFunction.apply(key, e.value);
1119                 if (mc != modCount) {
1120                     throw new ConcurrentModificationException();
1121                 }
1122                 if (newValue == null) {
1123                     if (prev != null) {
1124                         prev.next = e.next;
1125                     } else {
1126                         tab[index] = e.next;
1127                     }
1128                     modCount = mc + 1;
1129                     count--;
1130                 } else {
1131                     e.value = newValue;
1132                 }
1133                 return newValue;
1134             }
1135         }
1136 
1137         int mc = modCount;
1138         V newValue = remappingFunction.apply(key, null);
1139         if (mc != modCount) { throw new ConcurrentModificationException(); }
1140         if (newValue != null) {
1141             addEntry(hash, key, newValue, index);
1142         }
1143 
1144         return newValue;
1145     }
1146 
1147     /**
1148      * {@inheritDoc}
1149      *
1150      * <p>This method will, on a best-effort basis, throw a
1151      * {@link java.util.ConcurrentModificationException} if the remapping
1152      * function modified this map during computation.
1153      *
1154      * @throws ConcurrentModificationException if it is detected that the
1155      * remapping function modified this map
1156      */
1157     @Override
merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)1158     public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
1159         Objects.requireNonNull(remappingFunction);
1160 
1161         Entry<?,?> tab[] = table;
1162         int hash = key.hashCode();
1163         int index = (hash & 0x7FFFFFFF) % tab.length;
1164         @SuppressWarnings("unchecked")
1165         Entry<K,V> e = (Entry<K,V>)tab[index];
1166         for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1167             if (e.hash == hash && e.key.equals(key)) {
1168                 int mc = modCount;
1169                 V newValue = remappingFunction.apply(e.value, value);
1170                 if (mc != modCount) {
1171                     throw new ConcurrentModificationException();
1172                 }
1173                 if (newValue == null) {
1174                     if (prev != null) {
1175                         prev.next = e.next;
1176                     } else {
1177                         tab[index] = e.next;
1178                     }
1179                     modCount = mc + 1;
1180                     count--;
1181                 } else {
1182                     e.value = newValue;
1183                 }
1184                 return newValue;
1185             }
1186         }
1187 
1188         if (value != null) {
1189             addEntry(hash, key, value, index);
1190         }
1191 
1192         return value;
1193     }
1194 
1195     /**
1196      * Save the state of the Hashtable to a stream (i.e., serialize it).
1197      *
1198      * @serialData The <i>capacity</i> of the Hashtable (the length of the
1199      *             bucket array) is emitted (int), followed by the
1200      *             <i>size</i> of the Hashtable (the number of key-value
1201      *             mappings), followed by the key (Object) and value (Object)
1202      *             for each key-value mapping represented by the Hashtable
1203      *             The key-value mappings are emitted in no particular order.
1204      */
1205     @java.io.Serial
writeObject(java.io.ObjectOutputStream s)1206     private void writeObject(java.io.ObjectOutputStream s)
1207             throws IOException {
1208         writeHashtable(s);
1209     }
1210 
1211     /**
1212      * Perform serialization of the Hashtable to an ObjectOutputStream.
1213      * The Properties class overrides this method.
1214      */
writeHashtable(java.io.ObjectOutputStream s)1215     void writeHashtable(java.io.ObjectOutputStream s)
1216             throws IOException {
1217         Entry<Object, Object> entryStack = null;
1218 
1219         synchronized (this) {
1220             // Write out the threshold and loadFactor
1221             s.defaultWriteObject();
1222 
1223             // Write out the length and count of elements
1224             s.writeInt(table.length);
1225             s.writeInt(count);
1226 
1227             // Stack copies of the entries in the table
1228             for (Entry<?, ?> entry : table) {
1229 
1230                 while (entry != null) {
1231                     entryStack =
1232                         new Entry<>(0, entry.key, entry.value, entryStack);
1233                     entry = entry.next;
1234                 }
1235             }
1236         }
1237 
1238         // Write out the key/value objects from the stacked entries
1239         while (entryStack != null) {
1240             s.writeObject(entryStack.key);
1241             s.writeObject(entryStack.value);
1242             entryStack = entryStack.next;
1243         }
1244     }
1245 
1246     /**
1247      * Called by Properties to write out a simulated threshold and loadfactor.
1248      */
defaultWriteHashtable(java.io.ObjectOutputStream s, int length, float loadFactor)1249     final void defaultWriteHashtable(java.io.ObjectOutputStream s, int length,
1250             float loadFactor) throws IOException {
1251         this.threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
1252         this.loadFactor = loadFactor;
1253         s.defaultWriteObject();
1254     }
1255 
1256     /**
1257      * Reconstitute the Hashtable from a stream (i.e., deserialize it).
1258      */
1259     @java.io.Serial
readObject(java.io.ObjectInputStream s)1260     private void readObject(java.io.ObjectInputStream s)
1261             throws IOException, ClassNotFoundException {
1262         readHashtable(s);
1263     }
1264 
1265     /**
1266      * Perform deserialization of the Hashtable from an ObjectInputStream.
1267      * The Properties class overrides this method.
1268      */
readHashtable(java.io.ObjectInputStream s)1269     void readHashtable(java.io.ObjectInputStream s)
1270             throws IOException, ClassNotFoundException {
1271         // Read in the threshold and loadFactor
1272         s.defaultReadObject();
1273 
1274         // Validate loadFactor (ignore threshold - it will be re-computed)
1275         if (loadFactor <= 0 || Float.isNaN(loadFactor))
1276             throw new StreamCorruptedException("Illegal Load: " + loadFactor);
1277 
1278         // Read the original length of the array and number of elements
1279         int origlength = s.readInt();
1280         int elements = s.readInt();
1281 
1282         // Validate # of elements
1283         if (elements < 0)
1284             throw new StreamCorruptedException("Illegal # of Elements: " + elements);
1285 
1286         // Clamp original length to be more than elements / loadFactor
1287         // (this is the invariant enforced with auto-growth)
1288         origlength = Math.max(origlength, (int)(elements / loadFactor) + 1);
1289 
1290         // Compute new length with a bit of room 5% + 3 to grow but
1291         // no larger than the clamped original length.  Make the length
1292         // odd if it's large enough, this helps distribute the entries.
1293         // Guard against the length ending up zero, that's not valid.
1294         int length = (int)((elements + elements / 20) / loadFactor) + 3;
1295         if (length > elements && (length & 1) == 0)
1296             length--;
1297         length = Math.min(length, origlength);
1298 
1299         if (length < 0) { // overflow
1300             length = origlength;
1301         }
1302 
1303         // Check Map.Entry[].class since it's the nearest public type to
1304         // what we're actually creating.
1305         SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, length);
1306         table = new Entry<?,?>[length];
1307         threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
1308         count = 0;
1309 
1310         // Read the number of elements and then all the key/value objects
1311         for (; elements > 0; elements--) {
1312             @SuppressWarnings("unchecked")
1313                 K key = (K)s.readObject();
1314             @SuppressWarnings("unchecked")
1315                 V value = (V)s.readObject();
1316             // sync is eliminated for performance
1317             reconstitutionPut(table, key, value);
1318         }
1319     }
1320 
1321     /**
1322      * The put method used by readObject. This is provided because put
1323      * is overridable and should not be called in readObject since the
1324      * subclass will not yet be initialized.
1325      *
1326      * <p>This differs from the regular put method in several ways. No
1327      * checking for rehashing is necessary since the number of elements
1328      * initially in the table is known. The modCount is not incremented and
1329      * there's no synchronization because we are creating a new instance.
1330      * Also, no return value is needed.
1331      */
reconstitutionPut(Entry<?,?>[] tab, K key, V value)1332     private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
1333         throws StreamCorruptedException
1334     {
1335         if (value == null) {
1336             throw new java.io.StreamCorruptedException();
1337         }
1338         // Makes sure the key is not already in the hashtable.
1339         // This should not happen in deserialized version.
1340         int hash = key.hashCode();
1341         int index = (hash & 0x7FFFFFFF) % tab.length;
1342         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
1343             if ((e.hash == hash) && e.key.equals(key)) {
1344                 throw new java.io.StreamCorruptedException();
1345             }
1346         }
1347         // Creates the new entry.
1348         @SuppressWarnings("unchecked")
1349             Entry<K,V> e = (Entry<K,V>)tab[index];
1350         tab[index] = new Entry<>(hash, key, value, e);
1351         count++;
1352     }
1353 
1354     /**
1355      * Hashtable bucket collision list entry
1356      */
1357     private static class Entry<K,V> implements Map.Entry<K,V> {
1358         final int hash;
1359         final K key;
1360         V value;
1361         Entry<K,V> next;
1362 
Entry(int hash, K key, V value, Entry<K,V> next)1363         protected Entry(int hash, K key, V value, Entry<K,V> next) {
1364             this.hash = hash;
1365             this.key =  key;
1366             this.value = value;
1367             this.next = next;
1368         }
1369 
1370         @SuppressWarnings("unchecked")
clone()1371         protected Object clone() {
1372             return new Entry<>(hash, key, value,
1373                                   (next==null ? null : (Entry<K,V>) next.clone()));
1374         }
1375 
1376         // Map.Entry Ops
1377 
getKey()1378         public K getKey() {
1379             return key;
1380         }
1381 
getValue()1382         public V getValue() {
1383             return value;
1384         }
1385 
setValue(V value)1386         public V setValue(V value) {
1387             if (value == null)
1388                 throw new NullPointerException();
1389 
1390             V oldValue = this.value;
1391             this.value = value;
1392             return oldValue;
1393         }
1394 
equals(Object o)1395         public boolean equals(Object o) {
1396             if (!(o instanceof Map.Entry))
1397                 return false;
1398             Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1399 
1400             return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
1401                (value==null ? e.getValue()==null : value.equals(e.getValue()));
1402         }
1403 
hashCode()1404         public int hashCode() {
1405             return hash ^ Objects.hashCode(value);
1406         }
1407 
toString()1408         public String toString() {
1409             return key.toString()+"="+value.toString();
1410         }
1411     }
1412 
1413     // Types of Enumerations/Iterations
1414     private static final int KEYS = 0;
1415     private static final int VALUES = 1;
1416     private static final int ENTRIES = 2;
1417 
1418     /**
1419      * A hashtable enumerator class.  This class implements both the
1420      * Enumeration and Iterator interfaces, but individual instances
1421      * can be created with the Iterator methods disabled.  This is necessary
1422      * to avoid unintentionally increasing the capabilities granted a user
1423      * by passing an Enumeration.
1424      */
1425     private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
1426         final Entry<?,?>[] table = Hashtable.this.table;
1427         int index = table.length;
1428         Entry<?,?> entry;
1429         Entry<?,?> lastReturned;
1430         final int type;
1431 
1432         /**
1433          * Indicates whether this Enumerator is serving as an Iterator
1434          * or an Enumeration.  (true -> Iterator).
1435          */
1436         final boolean iterator;
1437 
1438         /**
1439          * The modCount value that the iterator believes that the backing
1440          * Hashtable should have.  If this expectation is violated, the iterator
1441          * has detected concurrent modification.
1442          */
1443         protected int expectedModCount = Hashtable.this.modCount;
1444 
Enumerator(int type, boolean iterator)1445         Enumerator(int type, boolean iterator) {
1446             this.type = type;
1447             this.iterator = iterator;
1448         }
1449 
hasMoreElements()1450         public boolean hasMoreElements() {
1451             Entry<?,?> e = entry;
1452             int i = index;
1453             Entry<?,?>[] t = table;
1454             /* Use locals for faster loop iteration */
1455             while (e == null && i > 0) {
1456                 e = t[--i];
1457             }
1458             entry = e;
1459             index = i;
1460             return e != null;
1461         }
1462 
1463         @SuppressWarnings("unchecked")
nextElement()1464         public T nextElement() {
1465             Entry<?,?> et = entry;
1466             int i = index;
1467             Entry<?,?>[] t = table;
1468             /* Use locals for faster loop iteration */
1469             while (et == null && i > 0) {
1470                 et = t[--i];
1471             }
1472             entry = et;
1473             index = i;
1474             if (et != null) {
1475                 Entry<?,?> e = lastReturned = entry;
1476                 entry = e.next;
1477                 return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
1478             }
1479             throw new NoSuchElementException("Hashtable Enumerator");
1480         }
1481 
1482         // Iterator methods
hasNext()1483         public boolean hasNext() {
1484             return hasMoreElements();
1485         }
1486 
next()1487         public T next() {
1488             if (Hashtable.this.modCount != expectedModCount)
1489                 throw new ConcurrentModificationException();
1490             return nextElement();
1491         }
1492 
remove()1493         public void remove() {
1494             if (!iterator)
1495                 throw new UnsupportedOperationException();
1496             if (lastReturned == null)
1497                 throw new IllegalStateException("Hashtable Enumerator");
1498             if (modCount != expectedModCount)
1499                 throw new ConcurrentModificationException();
1500 
1501             synchronized(Hashtable.this) {
1502                 Entry<?,?>[] tab = Hashtable.this.table;
1503                 int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
1504 
1505                 @SuppressWarnings("unchecked")
1506                 Entry<K,V> e = (Entry<K,V>)tab[index];
1507                 for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1508                     if (e == lastReturned) {
1509                         if (prev == null)
1510                             tab[index] = e.next;
1511                         else
1512                             prev.next = e.next;
1513                         expectedModCount++;
1514                         lastReturned = null;
1515                         Hashtable.this.modCount++;
1516                         Hashtable.this.count--;
1517                         return;
1518                     }
1519                 }
1520                 throw new ConcurrentModificationException();
1521             }
1522         }
1523     }
1524 }
1525