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