• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package java.util;
28 
29 import java.io.*;
30 import java.util.function.BiConsumer;
31 import java.util.function.BiFunction;
32 import java.util.function.Function;
33 import jdk.internal.misc.SharedSecrets;
34 
35 /**
36  * This class implements a hash table, which maps keys to values. Any
37  * non-{@code null} object can be used as a key or as a value. <p>
38  *
39  * To successfully store and retrieve objects from a hashtable, the
40  * objects used as keys must implement the {@code hashCode}
41  * method and the {@code equals} method. <p>
42  *
43  * An instance of {@code Hashtable} has two parameters that affect its
44  * performance: <i>initial capacity</i> and <i>load factor</i>.  The
45  * <i>capacity</i> is the number of <i>buckets</i> in the hash table, and the
46  * <i>initial capacity</i> is simply the capacity at the time the hash table
47  * is created.  Note that the hash table is <i>open</i>: in the case of a "hash
48  * collision", a single bucket stores multiple entries, which must be searched
49  * sequentially.  The <i>load factor</i> is a measure of how full the hash
50  * table is allowed to get before its capacity is automatically increased.
51  * The initial capacity and load factor parameters are merely hints to
52  * the implementation.  The exact details as to when and whether the rehash
53  * method is invoked are implementation-dependent.<p>
54  *
55  * Generally, the default load factor (.75) offers a good tradeoff between
56  * time and space costs.  Higher values decrease the space overhead but
57  * increase the time cost to look up an entry (which is reflected in most
58  * {@code Hashtable} operations, including {@code get} and {@code put}).<p>
59  *
60  * The initial capacity controls a tradeoff between wasted space and the
61  * need for {@code rehash} operations, which are time-consuming.
62  * No {@code rehash} operations will <i>ever</i> occur if the initial
63  * capacity is greater than the maximum number of entries the
64  * {@code Hashtable} will contain divided by its load factor.  However,
65  * setting the initial capacity too high can waste space.<p>
66  *
67  * If many entries are to be made into a {@code Hashtable},
68  * creating it with a sufficiently large capacity may allow the
69  * entries to be inserted more efficiently than letting it perform
70  * automatic rehashing as needed to grow the table. <p>
71  *
72  * This example creates a hashtable of numbers. It uses the names of
73  * the numbers as keys:
74  * <pre>   {@code
75  *   Hashtable<String, Integer> numbers
76  *     = new Hashtable<String, Integer>();
77  *   numbers.put("one", 1);
78  *   numbers.put("two", 2);
79  *   numbers.put("three", 3);}</pre>
80  *
81  * <p>To retrieve a number, use the following code:
82  * <pre>   {@code
83  *   Integer n = numbers.get("two");
84  *   if (n != null) {
85  *     System.out.println("two = " + n);
86  *   }}</pre>
87  *
88  * <p>The iterators returned by the {@code iterator} method of the collections
89  * returned by all of this class's "collection view methods" are
90  * <em>fail-fast</em>: if the Hashtable is structurally modified at any time
91  * after the iterator is created, in any way except through the iterator's own
92  * {@code remove} method, the iterator will throw a {@link
93  * ConcurrentModificationException}.  Thus, in the face of concurrent
94  * modification, the iterator fails quickly and cleanly, rather than risking
95  * arbitrary, non-deterministic behavior at an undetermined time in the future.
96  * The Enumerations returned by Hashtable's {@link #keys keys} and
97  * {@link #elements elements} methods are <em>not</em> fail-fast; if the
98  * Hashtable is structurally modified at any time after the enumeration is
99  * created then the results of enumerating are undefined.
100  *
101  * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
102  * as it is, generally speaking, impossible to make any hard guarantees in the
103  * presence of unsynchronized concurrent modification.  Fail-fast iterators
104  * throw {@code ConcurrentModificationException} on a best-effort basis.
105  * Therefore, it would be wrong to write a program that depended on this
106  * exception for its correctness: <i>the fail-fast behavior of iterators
107  * should be used only to detect bugs.</i>
108  *
109  * <p>As of the Java 2 platform v1.2, this class was retrofitted to
110  * implement the {@link Map} interface, making it a member of the
111  * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
112  *
113  * Java Collections Framework</a>.  Unlike the new collection
114  * implementations, {@code Hashtable} is synchronized.  If a
115  * thread-safe implementation is not needed, it is recommended to use
116  * {@link HashMap} in place of {@code Hashtable}.  If a thread-safe
117  * highly-concurrent implementation is desired, then it is recommended
118  * to use {@link java.util.concurrent.ConcurrentHashMap} in place of
119  * {@code Hashtable}.
120  *
121  * @param <K> the type of keys maintained by this map
122  * @param <V> the type of mapped values
123  *
124  * @author  Arthur van Hoff
125  * @author  Josh Bloch
126  * @author  Neal Gafter
127  * @see     Object#equals(java.lang.Object)
128  * @see     Object#hashCode()
129  * @see     Hashtable#rehash()
130  * @see     Collection
131  * @see     Map
132  * @see     HashMap
133  * @see     TreeMap
134  * @since 1.0
135  */
136 public class Hashtable<K,V>
137     extends Dictionary<K,V>
138     implements Map<K,V>, Cloneable, java.io.Serializable {
139 
140     /**
141      * The hash table data.
142      */
143     private transient HashtableEntry<?,?>[] table;
144 
145     /**
146      * The total number of entries in the hash table.
147      */
148     private transient int count;
149 
150     /**
151      * The table is rehashed when its size exceeds this threshold.  (The
152      * value of this field is (int)(capacity * loadFactor).)
153      *
154      * @serial
155      */
156     private int threshold;
157 
158     /**
159      * The load factor for the hashtable.
160      *
161      * @serial
162      */
163     private float loadFactor;
164 
165     /**
166      * The number of times this Hashtable has been structurally modified
167      * Structural modifications are those that change the number of entries in
168      * the Hashtable or otherwise modify its internal structure (e.g.,
169      * rehash).  This field is used to make iterators on Collection-views of
170      * the Hashtable fail-fast.  (See ConcurrentModificationException).
171      */
172     private transient int modCount = 0;
173 
174     /** use serialVersionUID from JDK 1.0.2 for interoperability */
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      * @exception  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 HashtableEntry<?,?>[initialCapacity];
197         // Android-changed: Ignore loadFactor when calculating threshold from initialCapacity
198         // threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
199         threshold = (int)Math.min(initialCapacity, MAX_ARRAY_SIZE + 1);
200     }
201 
202     /**
203      * Constructs a new, empty hashtable with the specified initial capacity
204      * and default load factor (0.75).
205      *
206      * @param     initialCapacity   the initial capacity of the hashtable.
207      * @exception IllegalArgumentException if the initial capacity is less
208      *              than zero.
209      */
Hashtable(int initialCapacity)210     public Hashtable(int initialCapacity) {
211         this(initialCapacity, 0.75f);
212     }
213 
214     /**
215      * Constructs a new, empty hashtable with a default initial capacity (11)
216      * and load factor (0.75).
217      */
Hashtable()218     public Hashtable() {
219         this(11, 0.75f);
220     }
221 
222     /**
223      * Constructs a new hashtable with the same mappings as the given
224      * Map.  The hashtable is created with an initial capacity sufficient to
225      * hold the mappings in the given Map and a default load factor (0.75).
226      *
227      * @param t the map whose mappings are to be placed in this map.
228      * @throws NullPointerException if the specified map is null.
229      * @since   1.2
230      */
Hashtable(Map<? extends K, ? extends V> t)231     public Hashtable(Map<? extends K, ? extends V> t) {
232         this(Math.max(2*t.size(), 11), 0.75f);
233         putAll(t);
234     }
235 
236     /**
237      * A constructor chained from {@link Properties} keeps Hashtable fields
238      * uninitialized since they are not used.
239      *
240      * @param dummy a dummy parameter
241      */
Hashtable(Void dummy)242     Hashtable(Void dummy) {}
243 
244     /**
245      * Returns the number of keys in this hashtable.
246      *
247      * @return  the number of keys in this hashtable.
248      */
size()249     public synchronized int size() {
250         return count;
251     }
252 
253     /**
254      * Tests if this hashtable maps no keys to values.
255      *
256      * @return  {@code true} if this hashtable maps no keys to values;
257      *          {@code false} otherwise.
258      */
isEmpty()259     public synchronized boolean isEmpty() {
260         return count == 0;
261     }
262 
263     /**
264      * Returns an enumeration of the keys in this hashtable.
265      * Use the Enumeration methods on the returned object to fetch the keys
266      * sequentially. If the hashtable is structurally modified while enumerating
267      * over the keys then the results of enumerating are undefined.
268      *
269      * @return  an enumeration of the keys in this hashtable.
270      * @see     Enumeration
271      * @see     #elements()
272      * @see     #keySet()
273      * @see     Map
274      */
keys()275     public synchronized Enumeration<K> keys() {
276         return this.<K>getEnumeration(KEYS);
277     }
278 
279     /**
280      * Returns an enumeration of the values in this hashtable.
281      * Use the Enumeration methods on the returned object to fetch the elements
282      * sequentially. If the hashtable is structurally modified while enumerating
283      * over the values then the results of enumerating are undefined.
284      *
285      * @return  an enumeration of the values in this hashtable.
286      * @see     java.util.Enumeration
287      * @see     #keys()
288      * @see     #values()
289      * @see     Map
290      */
elements()291     public synchronized Enumeration<V> elements() {
292         return this.<V>getEnumeration(VALUES);
293     }
294 
295     /**
296      * Tests if some key maps into the specified value in this hashtable.
297      * This operation is more expensive than the {@link #containsKey
298      * containsKey} method.
299      *
300      * <p>Note that this method is identical in functionality to
301      * {@link #containsValue containsValue}, (which is part of the
302      * {@link Map} interface in the collections framework).
303      *
304      * @param      value   a value to search for
305      * @return     {@code true} if and only if some key maps to the
306      *             {@code value} argument in this hashtable as
307      *             determined by the {@code equals} method;
308      *             {@code false} otherwise.
309      * @exception  NullPointerException  if the value is {@code null}
310      */
contains(Object value)311     public synchronized boolean contains(Object value) {
312         if (value == null) {
313             throw new NullPointerException();
314         }
315 
316         HashtableEntry<?,?> tab[] = table;
317         for (int i = tab.length ; i-- > 0 ;) {
318             for (HashtableEntry<?,?> e = tab[i] ; e != null ; e = e.next) {
319                 if (e.value.equals(value)) {
320                     return true;
321                 }
322             }
323         }
324         return false;
325     }
326 
327     /**
328      * Returns true if this hashtable maps one or more keys to this value.
329      *
330      * <p>Note that this method is identical in functionality to {@link
331      * #contains contains} (which predates the {@link Map} interface).
332      *
333      * @param value value whose presence in this hashtable is to be tested
334      * @return {@code true} if this map maps one or more keys to the
335      *         specified value
336      * @throws NullPointerException  if the value is {@code null}
337      * @since 1.2
338      */
containsValue(Object value)339     public boolean containsValue(Object value) {
340         return contains(value);
341     }
342 
343     /**
344      * Tests if the specified object is a key in this hashtable.
345      *
346      * @param   key   possible key
347      * @return  {@code true} if and only if the specified object
348      *          is a key in this hashtable, as determined by the
349      *          {@code equals} method; {@code false} otherwise.
350      * @throws  NullPointerException  if the key is {@code null}
351      * @see     #contains(Object)
352      */
containsKey(Object key)353     public synchronized boolean containsKey(Object key) {
354         HashtableEntry<?,?> tab[] = table;
355         int hash = key.hashCode();
356         int index = (hash & 0x7FFFFFFF) % tab.length;
357         for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
358             if ((e.hash == hash) && e.key.equals(key)) {
359                 return true;
360             }
361         }
362         return false;
363     }
364 
365     /**
366      * Returns the value to which the specified key is mapped,
367      * or {@code null} if this map contains no mapping for the key.
368      *
369      * <p>More formally, if this map contains a mapping from a key
370      * {@code k} to a value {@code v} such that {@code (key.equals(k))},
371      * then this method returns {@code v}; otherwise it returns
372      * {@code null}.  (There can be at most one such mapping.)
373      *
374      * @param key the key whose associated value is to be returned
375      * @return the value to which the specified key is mapped, or
376      *         {@code null} if this map contains no mapping for the key
377      * @throws NullPointerException if the specified key is null
378      * @see     #put(Object, Object)
379      */
380     @SuppressWarnings("unchecked")
get(Object key)381     public synchronized V get(Object key) {
382         HashtableEntry<?,?> tab[] = table;
383         int hash = key.hashCode();
384         int index = (hash & 0x7FFFFFFF) % tab.length;
385         for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
386             if ((e.hash == hash) && e.key.equals(key)) {
387                 return (V)e.value;
388             }
389         }
390         return null;
391     }
392 
393     /**
394      * The maximum size of array to allocate.
395      * Some VMs reserve some header words in an array.
396      * Attempts to allocate larger arrays may result in
397      * OutOfMemoryError: Requested array size exceeds VM limit
398      */
399     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
400 
401     /**
402      * Increases the capacity of and internally reorganizes this
403      * hashtable, in order to accommodate and access its entries more
404      * efficiently.  This method is called automatically when the
405      * number of keys in the hashtable exceeds this hashtable's capacity
406      * and load factor.
407      */
408     @SuppressWarnings("unchecked")
rehash()409     protected void rehash() {
410         int oldCapacity = table.length;
411         HashtableEntry<?,?>[] oldMap = table;
412 
413         // overflow-conscious code
414         int newCapacity = (oldCapacity << 1) + 1;
415         if (newCapacity - MAX_ARRAY_SIZE > 0) {
416             if (oldCapacity == MAX_ARRAY_SIZE)
417                 // Keep running with MAX_ARRAY_SIZE buckets
418                 return;
419             newCapacity = MAX_ARRAY_SIZE;
420         }
421         HashtableEntry<?,?>[] newMap = new HashtableEntry<?,?>[newCapacity];
422 
423         modCount++;
424         threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
425         table = newMap;
426 
427         for (int i = oldCapacity ; i-- > 0 ;) {
428             for (HashtableEntry<K,V> old = (HashtableEntry<K,V>)oldMap[i] ; old != null ; ) {
429                 HashtableEntry<K,V> e = old;
430                 old = old.next;
431 
432                 int index = (e.hash & 0x7FFFFFFF) % newCapacity;
433                 e.next = (HashtableEntry<K,V>)newMap[index];
434                 newMap[index] = e;
435             }
436         }
437     }
438 
addEntry(int hash, K key, V value, int index)439     private void addEntry(int hash, K key, V value, int index) {
440         HashtableEntry<?,?> tab[] = table;
441         if (count >= threshold) {
442             // Rehash the table if the threshold is exceeded
443             rehash();
444 
445             tab = table;
446             hash = key.hashCode();
447             index = (hash & 0x7FFFFFFF) % tab.length;
448         }
449 
450         // Creates the new entry.
451         @SuppressWarnings("unchecked")
452         HashtableEntry<K,V> e = (HashtableEntry<K,V>) tab[index];
453         tab[index] = new HashtableEntry<>(hash, key, value, e);
454         count++;
455         modCount++;
456     }
457 
458     /**
459      * Maps the specified {@code key} to the specified
460      * {@code value} in this hashtable. Neither the key nor the
461      * value can be {@code null}. <p>
462      *
463      * The value can be retrieved by calling the {@code get} method
464      * with a key that is equal to the original key.
465      *
466      * @param      key     the hashtable key
467      * @param      value   the value
468      * @return     the previous value of the specified key in this hashtable,
469      *             or {@code null} if it did not have one
470      * @exception  NullPointerException  if the key or value is
471      *               {@code null}
472      * @see     Object#equals(Object)
473      * @see     #get(Object)
474      */
put(K key, V value)475     public synchronized V put(K key, V value) {
476         // Make sure the value is not null
477         if (value == null) {
478             throw new NullPointerException();
479         }
480 
481         // Makes sure the key is not already in the hashtable.
482         HashtableEntry<?,?> tab[] = table;
483         int hash = key.hashCode();
484         int index = (hash & 0x7FFFFFFF) % tab.length;
485         @SuppressWarnings("unchecked")
486         HashtableEntry<K,V> entry = (HashtableEntry<K,V>)tab[index];
487         for(; entry != null ; entry = entry.next) {
488             if ((entry.hash == hash) && entry.key.equals(key)) {
489                 V old = entry.value;
490                 entry.value = value;
491                 return old;
492             }
493         }
494 
495         addEntry(hash, key, value, index);
496         return null;
497     }
498 
499     /**
500      * Removes the key (and its corresponding value) from this
501      * hashtable. This method does nothing if the key is not in the hashtable.
502      *
503      * @param   key   the key that needs to be removed
504      * @return  the value to which the key had been mapped in this hashtable,
505      *          or {@code null} if the key did not have a mapping
506      * @throws  NullPointerException  if the key is {@code null}
507      */
remove(Object key)508     public synchronized V remove(Object key) {
509         HashtableEntry<?,?> tab[] = table;
510         int hash = key.hashCode();
511         int index = (hash & 0x7FFFFFFF) % tab.length;
512         @SuppressWarnings("unchecked")
513         HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
514         for(HashtableEntry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
515             if ((e.hash == hash) && e.key.equals(key)) {
516                 if (prev != null) {
517                     prev.next = e.next;
518                 } else {
519                     tab[index] = e.next;
520                 }
521                 modCount++;
522                 count--;
523                 V oldValue = e.value;
524                 e.value = null;
525                 return oldValue;
526             }
527         }
528         return null;
529     }
530 
531     /**
532      * Copies all of the mappings from the specified map to this hashtable.
533      * These mappings will replace any mappings that this hashtable had for any
534      * of the keys currently in the specified map.
535      *
536      * @param t mappings to be stored in this map
537      * @throws NullPointerException if the specified map is null
538      * @since 1.2
539      */
putAll(Map<? extends K, ? extends V> t)540     public synchronized void putAll(Map<? extends K, ? extends V> t) {
541         for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
542             put(e.getKey(), e.getValue());
543     }
544 
545     /**
546      * Clears this hashtable so that it contains no keys.
547      */
clear()548     public synchronized void clear() {
549         HashtableEntry<?,?> tab[] = table;
550         for (int index = tab.length; --index >= 0; )
551             tab[index] = null;
552         modCount++;
553         count = 0;
554     }
555 
556     /**
557      * Creates a shallow copy of this hashtable. All the structure of the
558      * hashtable itself is copied, but the keys and values are not cloned.
559      * This is a relatively expensive operation.
560      *
561      * @return  a clone of the hashtable
562      */
clone()563     public synchronized Object clone() {
564         Hashtable<?,?> t = cloneHashtable();
565         t.table = new HashtableEntry<?,?>[table.length];
566         for (int i = table.length ; i-- > 0 ; ) {
567             t.table[i] = (table[i] != null)
568                 ? (HashtableEntry<?,?>) table[i].clone() : null;
569         }
570         t.keySet = null;
571         t.entrySet = null;
572         t.values = null;
573         t.modCount = 0;
574         return t;
575     }
576 
577     /** Calls super.clone() */
cloneHashtable()578     final Hashtable<?,?> cloneHashtable() {
579         try {
580             return (Hashtable<?,?>)super.clone();
581         } catch (CloneNotSupportedException e) {
582             // this shouldn't happen, since we are Cloneable
583             throw new InternalError(e);
584         }
585     }
586 
587     /**
588      * Returns a string representation of this {@code Hashtable} object
589      * in the form of a set of entries, enclosed in braces and separated
590      * by the ASCII characters "<code> ,&nbsp;</code>" (comma and space). Each
591      * entry is rendered as the key, an equals sign {@code =}, and the
592      * associated element, where the {@code toString} method is used to
593      * convert the key and element to strings.
594      *
595      * @return  a string representation of this hashtable
596      */
toString()597     public synchronized String toString() {
598         int max = size() - 1;
599         if (max == -1)
600             return "{}";
601 
602         StringBuilder sb = new StringBuilder();
603         Iterator<Map.Entry<K,V>> it = entrySet().iterator();
604 
605         sb.append('{');
606         for (int i = 0; ; i++) {
607             Map.Entry<K,V> e = it.next();
608             K key = e.getKey();
609             V value = e.getValue();
610             sb.append(key   == this ? "(this Map)" : key.toString());
611             sb.append('=');
612             sb.append(value == this ? "(this Map)" : value.toString());
613 
614             if (i == max)
615                 return sb.append('}').toString();
616             sb.append(", ");
617         }
618     }
619 
620 
getEnumeration(int type)621     private <T> Enumeration<T> getEnumeration(int type) {
622         if (count == 0) {
623             return Collections.emptyEnumeration();
624         } else {
625             return new Enumerator<>(type, false);
626         }
627     }
628 
getIterator(int type)629     private <T> Iterator<T> getIterator(int type) {
630         if (count == 0) {
631             return Collections.emptyIterator();
632         } else {
633             return new Enumerator<>(type, true);
634         }
635     }
636 
637     // Views
638 
639     /**
640      * Each of these fields are initialized to contain an instance of the
641      * appropriate view the first time this view is requested.  The views are
642      * stateless, so there's no reason to create more than one of each.
643      */
644     private transient volatile Set<K> keySet;
645     private transient volatile Set<Map.Entry<K,V>> entrySet;
646     private transient volatile Collection<V> values;
647 
648     /**
649      * Returns a {@link Set} view of the keys contained in this map.
650      * The set is backed by the map, so changes to the map are
651      * reflected in the set, and vice-versa.  If the map is modified
652      * while an iteration over the set is in progress (except through
653      * the iterator's own {@code remove} operation), the results of
654      * the iteration are undefined.  The set supports element removal,
655      * which removes the corresponding mapping from the map, via the
656      * {@code Iterator.remove}, {@code Set.remove},
657      * {@code removeAll}, {@code retainAll}, and {@code clear}
658      * operations.  It does not support the {@code add} or {@code addAll}
659      * operations.
660      *
661      * @since 1.2
662      */
keySet()663     public Set<K> keySet() {
664         if (keySet == null)
665             keySet = Collections.synchronizedSet(new KeySet(), this);
666         return keySet;
667     }
668 
669     private class KeySet extends AbstractSet<K> {
iterator()670         public Iterator<K> iterator() {
671             return getIterator(KEYS);
672         }
size()673         public int size() {
674             return count;
675         }
contains(Object o)676         public boolean contains(Object o) {
677             return containsKey(o);
678         }
remove(Object o)679         public boolean remove(Object o) {
680             return Hashtable.this.remove(o) != null;
681         }
clear()682         public void clear() {
683             Hashtable.this.clear();
684         }
685     }
686 
687     /**
688      * Returns a {@link Set} view of the mappings contained in this map.
689      * The set is backed by the map, so changes to the map are
690      * reflected in the set, and vice-versa.  If the map is modified
691      * while an iteration over the set is in progress (except through
692      * the iterator's own {@code remove} operation, or through the
693      * {@code setValue} operation on a map entry returned by the
694      * iterator) the results of the iteration are undefined.  The set
695      * supports element removal, which removes the corresponding
696      * mapping from the map, via the {@code Iterator.remove},
697      * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
698      * {@code clear} operations.  It does not support the
699      * {@code add} or {@code addAll} operations.
700      *
701      * @since 1.2
702      */
entrySet()703     public Set<Map.Entry<K,V>> entrySet() {
704         if (entrySet==null)
705             entrySet = Collections.synchronizedSet(new EntrySet(), this);
706         return entrySet;
707     }
708 
709     private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
iterator()710         public Iterator<Map.Entry<K,V>> iterator() {
711             return getIterator(ENTRIES);
712         }
713 
add(Map.Entry<K,V> o)714         public boolean add(Map.Entry<K,V> o) {
715             return super.add(o);
716         }
717 
contains(Object o)718         public boolean contains(Object o) {
719             if (!(o instanceof Map.Entry))
720                 return false;
721             Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
722             Object key = entry.getKey();
723             HashtableEntry<?,?>[] tab = table;
724             int hash = key.hashCode();
725             int index = (hash & 0x7FFFFFFF) % tab.length;
726 
727             for (HashtableEntry<?,?> e = tab[index]; e != null; e = e.next)
728                 if (e.hash==hash && e.equals(entry))
729                     return true;
730             return false;
731         }
732 
remove(Object o)733         public boolean remove(Object o) {
734             if (!(o instanceof Map.Entry))
735                 return false;
736             Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
737             Object key = entry.getKey();
738             HashtableEntry<?,?>[] tab = table;
739             int hash = key.hashCode();
740             int index = (hash & 0x7FFFFFFF) % tab.length;
741 
742             @SuppressWarnings("unchecked")
743             HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
744             for(HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
745                 if (e.hash==hash && e.equals(entry)) {
746                     if (prev != null)
747                         prev.next = e.next;
748                     else
749                         tab[index] = e.next;
750 
751                     e.value = null; // clear for gc.
752                     modCount++;
753                     count--;
754                     return true;
755                 }
756             }
757             return false;
758         }
759 
size()760         public int size() {
761             return count;
762         }
763 
clear()764         public void clear() {
765             Hashtable.this.clear();
766         }
767     }
768 
769     /**
770      * Returns a {@link Collection} view of the values contained in this map.
771      * The collection is backed by the map, so changes to the map are
772      * reflected in the collection, and vice-versa.  If the map is
773      * modified while an iteration over the collection is in progress
774      * (except through the iterator's own {@code remove} operation),
775      * the results of the iteration are undefined.  The collection
776      * supports element removal, which removes the corresponding
777      * mapping from the map, via the {@code Iterator.remove},
778      * {@code Collection.remove}, {@code removeAll},
779      * {@code retainAll} and {@code clear} operations.  It does not
780      * support the {@code add} or {@code addAll} operations.
781      *
782      * @since 1.2
783      */
values()784     public Collection<V> values() {
785         if (values==null)
786             values = Collections.synchronizedCollection(new ValueCollection(),
787                                                         this);
788         return values;
789     }
790 
791     private class ValueCollection extends AbstractCollection<V> {
iterator()792         public Iterator<V> iterator() {
793             return getIterator(VALUES);
794         }
size()795         public int size() {
796             return count;
797         }
contains(Object o)798         public boolean contains(Object o) {
799             return containsValue(o);
800         }
clear()801         public void clear() {
802             Hashtable.this.clear();
803         }
804     }
805 
806     // Comparison and hashing
807 
808     /**
809      * Compares the specified Object with this Map for equality,
810      * as per the definition in the Map interface.
811      *
812      * @param  o object to be compared for equality with this hashtable
813      * @return true if the specified Object is equal to this Map
814      * @see Map#equals(Object)
815      * @since 1.2
816      */
equals(Object o)817     public synchronized boolean equals(Object o) {
818         if (o == this)
819             return true;
820 
821         if (!(o instanceof Map))
822             return false;
823         Map<?,?> t = (Map<?,?>) o;
824         if (t.size() != size())
825             return false;
826 
827         try {
828             for (Map.Entry<K, V> e : entrySet()) {
829                 K key = e.getKey();
830                 V value = e.getValue();
831                 if (value == null) {
832                     if (!(t.get(key) == null && t.containsKey(key)))
833                         return false;
834                 } else {
835                     if (!value.equals(t.get(key)))
836                         return false;
837                 }
838             }
839         } catch (ClassCastException unused)   {
840             return false;
841         } catch (NullPointerException unused) {
842             return false;
843         }
844 
845         return true;
846     }
847 
848     /**
849      * Returns the hash code value for this Map as per the definition in the
850      * Map interface.
851      *
852      * @see Map#hashCode()
853      * @since 1.2
854      */
hashCode()855     public synchronized int hashCode() {
856         /*
857          * This code detects the recursion caused by computing the hash code
858          * of a self-referential hash table and prevents the stack overflow
859          * that would otherwise result.  This allows certain 1.1-era
860          * applets with self-referential hash tables to work.  This code
861          * abuses the loadFactor field to do double-duty as a hashCode
862          * in progress flag, so as not to worsen the space performance.
863          * A negative load factor indicates that hash code computation is
864          * in progress.
865          */
866         int h = 0;
867         if (count == 0 || loadFactor < 0)
868             return h;  // Returns zero
869 
870         loadFactor = -loadFactor;  // Mark hashCode computation in progress
871         HashtableEntry<?,?>[] tab = table;
872         for (HashtableEntry<?,?> entry : tab) {
873             while (entry != null) {
874                 h += entry.hashCode();
875                 entry = entry.next;
876             }
877         }
878 
879         loadFactor = -loadFactor;  // Mark hashCode computation complete
880 
881         return h;
882     }
883 
884     @Override
getOrDefault(Object key, V defaultValue)885     public synchronized V getOrDefault(Object key, V defaultValue) {
886         V result = get(key);
887         return (null == result) ? defaultValue : result;
888     }
889 
890     @SuppressWarnings("unchecked")
891     @Override
forEach(BiConsumer<? super K, ? super V> action)892     public synchronized void forEach(BiConsumer<? super K, ? super V> action) {
893         Objects.requireNonNull(action);     // explicit check required in case
894                                             // table is empty.
895         final int expectedModCount = modCount;
896 
897         HashtableEntry<?, ?>[] tab = table;
898         for (HashtableEntry<?, ?> entry : tab) {
899             while (entry != null) {
900                 action.accept((K)entry.key, (V)entry.value);
901                 entry = entry.next;
902 
903                 if (expectedModCount != modCount) {
904                     throw new ConcurrentModificationException();
905                 }
906             }
907         }
908     }
909 
910     @SuppressWarnings("unchecked")
911     @Override
replaceAll(BiFunction<? super K, ? super V, ? extends V> function)912     public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
913         Objects.requireNonNull(function);     // explicit check required in case
914                                               // table is empty.
915         final int expectedModCount = modCount;
916 
917         HashtableEntry<K, V>[] tab = (HashtableEntry<K, V>[])table;
918         for (HashtableEntry<K, V> entry : tab) {
919             while (entry != null) {
920                 entry.value = Objects.requireNonNull(
921                     function.apply(entry.key, entry.value));
922                 entry = entry.next;
923 
924                 if (expectedModCount != modCount) {
925                     throw new ConcurrentModificationException();
926                 }
927             }
928         }
929     }
930 
931     @Override
putIfAbsent(K key, V value)932     public synchronized V putIfAbsent(K key, V value) {
933         Objects.requireNonNull(value);
934 
935         // Makes sure the key is not already in the hashtable.
936         HashtableEntry<?,?> tab[] = table;
937         int hash = key.hashCode();
938         int index = (hash & 0x7FFFFFFF) % tab.length;
939         @SuppressWarnings("unchecked")
940         HashtableEntry<K,V> entry = (HashtableEntry<K,V>)tab[index];
941         for (; entry != null; entry = entry.next) {
942             if ((entry.hash == hash) && entry.key.equals(key)) {
943                 V old = entry.value;
944                 if (old == null) {
945                     entry.value = value;
946                 }
947                 return old;
948             }
949         }
950 
951         addEntry(hash, key, value, index);
952         return null;
953     }
954 
955     @Override
remove(Object key, Object value)956     public synchronized boolean remove(Object key, Object value) {
957         Objects.requireNonNull(value);
958 
959         HashtableEntry<?,?> tab[] = table;
960         int hash = key.hashCode();
961         int index = (hash & 0x7FFFFFFF) % tab.length;
962         @SuppressWarnings("unchecked")
963         HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
964         for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
965             if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {
966                 if (prev != null) {
967                     prev.next = e.next;
968                 } else {
969                     tab[index] = e.next;
970                 }
971                 e.value = null; // clear for gc
972                 modCount++;
973                 count--;
974                 return true;
975             }
976         }
977         return false;
978     }
979 
980     @Override
replace(K key, V oldValue, V newValue)981     public synchronized boolean replace(K key, V oldValue, V newValue) {
982         Objects.requireNonNull(oldValue);
983         Objects.requireNonNull(newValue);
984         HashtableEntry<?,?> tab[] = table;
985         int hash = key.hashCode();
986         int index = (hash & 0x7FFFFFFF) % tab.length;
987         @SuppressWarnings("unchecked")
988         HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
989         for (; e != null; e = e.next) {
990             if ((e.hash == hash) && e.key.equals(key)) {
991                 if (e.value.equals(oldValue)) {
992                     e.value = newValue;
993                     return true;
994                 } else {
995                     return false;
996                 }
997             }
998         }
999         return false;
1000     }
1001 
1002     @Override
replace(K key, V value)1003     public synchronized V replace(K key, V value) {
1004         Objects.requireNonNull(value);
1005         HashtableEntry<?,?> tab[] = table;
1006         int hash = key.hashCode();
1007         int index = (hash & 0x7FFFFFFF) % tab.length;
1008         @SuppressWarnings("unchecked")
1009         HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
1010         for (; e != null; e = e.next) {
1011             if ((e.hash == hash) && e.key.equals(key)) {
1012                 V oldValue = e.value;
1013                 e.value = value;
1014                 return oldValue;
1015             }
1016         }
1017         return null;
1018     }
1019 
1020     /**
1021      * {@inheritDoc}
1022      *
1023      * <p>This method will, on a best-effort basis, throw a
1024      * {@link java.util.ConcurrentModificationException} if the mapping
1025      * function modified this map during computation.
1026      *
1027      * @throws ConcurrentModificationException if it is detected that the
1028      * mapping function modified this map
1029      */
1030     @Override
computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)1031     public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
1032         Objects.requireNonNull(mappingFunction);
1033 
1034         HashtableEntry<?,?> tab[] = table;
1035         int hash = key.hashCode();
1036         int index = (hash & 0x7FFFFFFF) % tab.length;
1037         @SuppressWarnings("unchecked")
1038         HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
1039         for (; e != null; e = e.next) {
1040             if (e.hash == hash && e.key.equals(key)) {
1041                 // Hashtable not accept null value
1042                 return e.value;
1043             }
1044         }
1045 
1046         int mc = modCount;
1047         V newValue = mappingFunction.apply(key);
1048         if (mc != modCount) { throw new ConcurrentModificationException(); }
1049         if (newValue != null) {
1050             addEntry(hash, key, newValue, index);
1051         }
1052 
1053         return newValue;
1054     }
1055 
1056     /**
1057      * {@inheritDoc}
1058      *
1059      * <p>This method will, on a best-effort basis, throw a
1060      * {@link java.util.ConcurrentModificationException} if the remapping
1061      * function modified this map during computation.
1062      *
1063      * @throws ConcurrentModificationException if it is detected that the
1064      * remapping function modified this map
1065      */
1066     @Override
computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)1067     public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
1068         Objects.requireNonNull(remappingFunction);
1069 
1070         HashtableEntry<?,?> tab[] = table;
1071         int hash = key.hashCode();
1072         int index = (hash & 0x7FFFFFFF) % tab.length;
1073         @SuppressWarnings("unchecked")
1074         HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
1075         for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
1076             if (e.hash == hash && e.key.equals(key)) {
1077                 int mc = modCount;
1078                 V newValue = remappingFunction.apply(key, e.value);
1079                 if (mc != modCount) {
1080                     throw new ConcurrentModificationException();
1081                 }
1082                 if (newValue == null) {
1083                     if (prev != null) {
1084                         prev.next = e.next;
1085                     } else {
1086                         tab[index] = e.next;
1087                     }
1088                     modCount = mc + 1;
1089                     count--;
1090                 } else {
1091                     e.value = newValue;
1092                 }
1093                 return newValue;
1094             }
1095         }
1096         return null;
1097     }
1098     /**
1099      * {@inheritDoc}
1100      *
1101      * <p>This method will, on a best-effort basis, throw a
1102      * {@link java.util.ConcurrentModificationException} if the remapping
1103      * function modified this map during computation.
1104      *
1105      * @throws ConcurrentModificationException if it is detected that the
1106      * remapping function modified this map
1107      */
1108     @Override
compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)1109     public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
1110         Objects.requireNonNull(remappingFunction);
1111 
1112         HashtableEntry<?,?> tab[] = table;
1113         int hash = key.hashCode();
1114         int index = (hash & 0x7FFFFFFF) % tab.length;
1115         @SuppressWarnings("unchecked")
1116         HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
1117         for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
1118             if (e.hash == hash && Objects.equals(e.key, key)) {
1119                 int mc = modCount;
1120                 V newValue = remappingFunction.apply(key, e.value);
1121                 if (mc != modCount) {
1122                     throw new ConcurrentModificationException();
1123                 }
1124                 if (newValue == null) {
1125                     if (prev != null) {
1126                         prev.next = e.next;
1127                     } else {
1128                         tab[index] = e.next;
1129                     }
1130                     modCount = mc + 1;
1131                     count--;
1132                 } else {
1133                     e.value = newValue;
1134                 }
1135                 return newValue;
1136             }
1137         }
1138 
1139         int mc = modCount;
1140         V newValue = remappingFunction.apply(key, null);
1141         if (mc != modCount) { throw new ConcurrentModificationException(); }
1142         if (newValue != null) {
1143             addEntry(hash, key, newValue, index);
1144         }
1145 
1146         return newValue;
1147     }
1148 
1149     /**
1150      * {@inheritDoc}
1151      *
1152      * <p>This method will, on a best-effort basis, throw a
1153      * {@link java.util.ConcurrentModificationException} if the remapping
1154      * function modified this map during computation.
1155      *
1156      * @throws ConcurrentModificationException if it is detected that the
1157      * remapping function modified this map
1158      */
1159     @Override
merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)1160     public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
1161         Objects.requireNonNull(remappingFunction);
1162 
1163         HashtableEntry<?,?> tab[] = table;
1164         int hash = key.hashCode();
1165         int index = (hash & 0x7FFFFFFF) % tab.length;
1166         @SuppressWarnings("unchecked")
1167         HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
1168         for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
1169             if (e.hash == hash && e.key.equals(key)) {
1170                 int mc = modCount;
1171                 V newValue = remappingFunction.apply(e.value, value);
1172                 if (mc != modCount) {
1173                     throw new ConcurrentModificationException();
1174                 }
1175                 if (newValue == null) {
1176                     if (prev != null) {
1177                         prev.next = e.next;
1178                     } else {
1179                         tab[index] = e.next;
1180                     }
1181                     modCount = mc + 1;
1182                     count--;
1183                 } else {
1184                     e.value = newValue;
1185                 }
1186                 return newValue;
1187             }
1188         }
1189 
1190         if (value != null) {
1191             addEntry(hash, key, value, index);
1192         }
1193 
1194         return value;
1195     }
1196 
1197     /**
1198      * Save the state of the Hashtable to a stream (i.e., serialize it).
1199      *
1200      * @serialData The <i>capacity</i> of the Hashtable (the length of the
1201      *             bucket array) is emitted (int), followed by the
1202      *             <i>size</i> of the Hashtable (the number of key-value
1203      *             mappings), followed by the key (Object) and value (Object)
1204      *             for each key-value mapping represented by the Hashtable
1205      *             The key-value mappings are emitted in no particular order.
1206      */
writeObject(java.io.ObjectOutputStream s)1207     private void writeObject(java.io.ObjectOutputStream s)
1208             throws IOException {
1209         writeHashtable(s);
1210     }
1211 
1212     /**
1213      * Perform serialization of the Hashtable to an ObjectOutputStream.
1214      * The Properties class overrides this method.
1215      */
writeHashtable(java.io.ObjectOutputStream s)1216     void writeHashtable(java.io.ObjectOutputStream s)
1217             throws IOException {
1218         HashtableEntry<Object, Object> entryStack = null;
1219 
1220         synchronized (this) {
1221             // Write out the threshold and loadFactor
1222             s.defaultWriteObject();
1223 
1224             // Write out the length and count of elements
1225             s.writeInt(table.length);
1226             s.writeInt(count);
1227 
1228             // Stack copies of the entries in the table
1229             for (HashtableEntry<?, ?> entry : table) {
1230 
1231                 while (entry != null) {
1232                     entryStack =
1233                         new HashtableEntry<>(0, entry.key, entry.value, entryStack);
1234                     entry = entry.next;
1235                 }
1236             }
1237         }
1238 
1239         // Write out the key/value objects from the stacked entries
1240         while (entryStack != null) {
1241             s.writeObject(entryStack.key);
1242             s.writeObject(entryStack.value);
1243             entryStack = entryStack.next;
1244         }
1245     }
1246 
1247     /**
1248      * Called by Properties to write out a simulated threshold and loadfactor.
1249      */
defaultWriteHashtable(java.io.ObjectOutputStream s, int length, float loadFactor)1250     final void defaultWriteHashtable(java.io.ObjectOutputStream s, int length,
1251             float loadFactor) throws IOException {
1252         // Android-changed: Ignore loadFactor when calculating threshold from initialCapacity
1253         // this.threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
1254         this.threshold = (int)Math.min(length, MAX_ARRAY_SIZE + 1);
1255         this.loadFactor = loadFactor;
1256         s.defaultWriteObject();
1257     }
1258 
1259     /**
1260      * Reconstitute the Hashtable from a stream (i.e., deserialize it).
1261      */
readObject(java.io.ObjectInputStream s)1262     private void readObject(java.io.ObjectInputStream s)
1263             throws IOException, ClassNotFoundException {
1264         readHashtable(s);
1265     }
1266 
1267     /**
1268      * Perform deserialization of the Hashtable from an ObjectInputStream.
1269      * The Properties class overrides this method.
1270      */
readHashtable(java.io.ObjectInputStream s)1271     void readHashtable(java.io.ObjectInputStream s)
1272             throws IOException, ClassNotFoundException {
1273         // Read in the threshold and loadFactor
1274         s.defaultReadObject();
1275 
1276         // Validate loadFactor (ignore threshold - it will be re-computed)
1277         if (loadFactor <= 0 || Float.isNaN(loadFactor))
1278             throw new StreamCorruptedException("Illegal Load: " + loadFactor);
1279 
1280         // Read the original length of the array and number of elements
1281         int origlength = s.readInt();
1282         int elements = s.readInt();
1283 
1284         // Validate # of elements
1285         if (elements < 0)
1286             throw new StreamCorruptedException("Illegal # of Elements: " + elements);
1287 
1288         // Clamp original length to be more than elements / loadFactor
1289         // (this is the invariant enforced with auto-growth)
1290         origlength = Math.max(origlength, (int)(elements / loadFactor) + 1);
1291 
1292         // Compute new length with a bit of room 5% + 3 to grow but
1293         // no larger than the clamped original length.  Make the length
1294         // odd if it's large enough, this helps distribute the entries.
1295         // Guard against the length ending up zero, that's not valid.
1296         int length = (int)((elements + elements / 20) / loadFactor) + 3;
1297         if (length > elements && (length & 1) == 0)
1298             length--;
1299         length = Math.min(length, origlength);
1300 
1301         if (length < 0) { // overflow
1302             length = origlength;
1303         }
1304 
1305         // Check Map.Entry[].class since it's the nearest public type to
1306         // what we're actually creating.
1307         SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, length);
1308         table = new HashtableEntry<?,?>[length];
1309         threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
1310         count = 0;
1311 
1312         // Read the number of elements and then all the key/value objects
1313         for (; elements > 0; elements--) {
1314             @SuppressWarnings("unchecked")
1315                 K key = (K)s.readObject();
1316             @SuppressWarnings("unchecked")
1317                 V value = (V)s.readObject();
1318             // sync is eliminated for performance
1319             reconstitutionPut(table, key, value);
1320         }
1321     }
1322 
1323     /**
1324      * The put method used by readObject. This is provided because put
1325      * is overridable and should not be called in readObject since the
1326      * subclass will not yet be initialized.
1327      *
1328      * <p>This differs from the regular put method in several ways. No
1329      * checking for rehashing is necessary since the number of elements
1330      * initially in the table is known. The modCount is not incremented and
1331      * there's no synchronization because we are creating a new instance.
1332      * Also, no return value is needed.
1333      */
reconstitutionPut(HashtableEntry<?,?>[] tab, K key, V value)1334     private void reconstitutionPut(HashtableEntry<?,?>[] tab, K key, V value)
1335         throws StreamCorruptedException
1336     {
1337         if (value == null) {
1338             throw new java.io.StreamCorruptedException();
1339         }
1340         // Makes sure the key is not already in the hashtable.
1341         // This should not happen in deserialized version.
1342         int hash = key.hashCode();
1343         int index = (hash & 0x7FFFFFFF) % tab.length;
1344         for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
1345             if ((e.hash == hash) && e.key.equals(key)) {
1346                 throw new java.io.StreamCorruptedException();
1347             }
1348         }
1349         // Creates the new entry.
1350         @SuppressWarnings("unchecked")
1351             HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
1352         tab[index] = new HashtableEntry<>(hash, key, value, e);
1353         count++;
1354     }
1355 
1356     /**
1357      * Hashtable bucket collision list entry
1358      */
1359     // BEGIN Android-changed: Renamed Entry -> HashtableEntry.
1360     // Code references to "HashTable.Entry" must mean Map.Entry
1361     //
1362     // This mirrors the corresponding rename of LinkedHashMap's
1363     // Entry->LinkedHashMapEntry.
1364     //
1365     // This is for source compatibility with earlier versions of Android.
1366     // Otherwise, it would hide Map.Entry which would break compilation
1367     // of code like:
1368     //
1369     // Hashtable.Entry<K, V> entry = hashtable.entrySet().iterator.next();
1370     //
1371     // To compile, that code snippet's "HashtableMap.Entry" must
1372     // mean java.util.Map.Entry which is the compile time type of
1373     // entrySet()'s elements.
1374     //
1375     private static class HashtableEntry<K,V> implements Map.Entry<K,V> {
1376     // END Android-changed: Renamed Entry -> HashtableEntry.
1377         final int hash;
1378         final K key;
1379         V value;
1380         HashtableEntry<K,V> next;
1381 
HashtableEntry(int hash, K key, V value, HashtableEntry<K,V> next)1382         protected HashtableEntry(int hash, K key, V value, HashtableEntry<K,V> next) {
1383             this.hash = hash;
1384             this.key =  key;
1385             this.value = value;
1386             this.next = next;
1387         }
1388 
1389         @SuppressWarnings("unchecked")
clone()1390         protected Object clone() {
1391             return new HashtableEntry<>(hash, key, value,
1392                                   (next==null ? null : (HashtableEntry<K,V>) next.clone()));
1393         }
1394 
1395         // Map.Entry Ops
1396 
getKey()1397         public K getKey() {
1398             return key;
1399         }
1400 
getValue()1401         public V getValue() {
1402             return value;
1403         }
1404 
setValue(V value)1405         public V setValue(V value) {
1406             if (value == null)
1407                 throw new NullPointerException();
1408 
1409             V oldValue = this.value;
1410             this.value = value;
1411             return oldValue;
1412         }
1413 
equals(Object o)1414         public boolean equals(Object o) {
1415             if (!(o instanceof Map.Entry))
1416                 return false;
1417             Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1418 
1419             return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
1420                (value==null ? e.getValue()==null : value.equals(e.getValue()));
1421         }
1422 
hashCode()1423         public int hashCode() {
1424             return hash ^ Objects.hashCode(value);
1425         }
1426 
toString()1427         public String toString() {
1428             return key.toString()+"="+value.toString();
1429         }
1430     }
1431 
1432     // Types of Enumerations/Iterations
1433     private static final int KEYS = 0;
1434     private static final int VALUES = 1;
1435     private static final int ENTRIES = 2;
1436 
1437     /**
1438      * A hashtable enumerator class.  This class implements both the
1439      * Enumeration and Iterator interfaces, but individual instances
1440      * can be created with the Iterator methods disabled.  This is necessary
1441      * to avoid unintentionally increasing the capabilities granted a user
1442      * by passing an Enumeration.
1443      */
1444     private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
1445         HashtableEntry<?,?>[] table = Hashtable.this.table;
1446         int index = table.length;
1447         HashtableEntry<?,?> entry;
1448         HashtableEntry<?,?> lastReturned;
1449         final int type;
1450 
1451         /**
1452          * Indicates whether this Enumerator is serving as an Iterator
1453          * or an Enumeration.  (true -> Iterator).
1454          */
1455         final boolean iterator;
1456 
1457         /**
1458          * The modCount value that the iterator believes that the backing
1459          * Hashtable should have.  If this expectation is violated, the iterator
1460          * has detected concurrent modification.
1461          */
1462         protected int expectedModCount = Hashtable.this.modCount;
1463 
Enumerator(int type, boolean iterator)1464         Enumerator(int type, boolean iterator) {
1465             this.type = type;
1466             this.iterator = iterator;
1467         }
1468 
hasMoreElements()1469         public boolean hasMoreElements() {
1470             HashtableEntry<?,?> e = entry;
1471             int i = index;
1472             HashtableEntry<?,?>[] t = table;
1473             /* Use locals for faster loop iteration */
1474             while (e == null && i > 0) {
1475                 e = t[--i];
1476             }
1477             entry = e;
1478             index = i;
1479             return e != null;
1480         }
1481 
1482         @SuppressWarnings("unchecked")
nextElement()1483         public T nextElement() {
1484             HashtableEntry<?,?> et = entry;
1485             int i = index;
1486             HashtableEntry<?,?>[] t = table;
1487             /* Use locals for faster loop iteration */
1488             while (et == null && i > 0) {
1489                 et = t[--i];
1490             }
1491             entry = et;
1492             index = i;
1493             if (et != null) {
1494                 HashtableEntry<?,?> e = lastReturned = entry;
1495                 entry = e.next;
1496                 return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
1497             }
1498             throw new NoSuchElementException("Hashtable Enumerator");
1499         }
1500 
1501         // Iterator methods
hasNext()1502         public boolean hasNext() {
1503             return hasMoreElements();
1504         }
1505 
next()1506         public T next() {
1507             if (Hashtable.this.modCount != expectedModCount)
1508                 throw new ConcurrentModificationException();
1509             return nextElement();
1510         }
1511 
remove()1512         public void remove() {
1513             if (!iterator)
1514                 throw new UnsupportedOperationException();
1515             if (lastReturned == null)
1516                 throw new IllegalStateException("Hashtable Enumerator");
1517             if (modCount != expectedModCount)
1518                 throw new ConcurrentModificationException();
1519 
1520             synchronized(Hashtable.this) {
1521                 HashtableEntry<?,?>[] tab = Hashtable.this.table;
1522                 int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
1523 
1524                 @SuppressWarnings("unchecked")
1525                 HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
1526                 for(HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
1527                     if (e == lastReturned) {
1528                         if (prev == null)
1529                             tab[index] = e.next;
1530                         else
1531                             prev.next = e.next;
1532                         expectedModCount++;
1533                         lastReturned = null;
1534                         Hashtable.this.modCount++;
1535                         Hashtable.this.count--;
1536                         return;
1537                     }
1538                 }
1539                 throw new ConcurrentModificationException();
1540             }
1541         }
1542     }
1543 }
1544