Home | History | Annotate | Download | only in util
      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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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")
    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")
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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 
    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      */
    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> {
    648         public Iterator<K> iterator() {
    649             return getIterator(KEYS);
    650         }
    651         public int size() {
    652             return count;
    653         }
    654         public boolean contains(Object o) {
    655             return containsKey(o);
    656         }
    657         public boolean remove(Object o) {
    658             return Hashtable.this.remove(o) != null;
    659         }
    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      */
    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>> {
    688         public Iterator<Map.Entry<K,V>> iterator() {
    689             return getIterator(ENTRIES);
    690         }
    691 
    692         public boolean add(Map.Entry<K,V> o) {
    693             return super.add(o);
    694         }
    695 
    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 
    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 
    738         public int size() {
    739             return count;
    740         }
    741 
    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      */
    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> {
    770         public Iterator<V> iterator() {
    771             return getIterator(VALUES);
    772         }
    773         public int size() {
    774             return count;
    775         }
    776         public boolean contains(Object o) {
    777             return containsValue(o);
    778         }
    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      */
    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      */
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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      */
   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      */
   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      */
   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 
   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")
   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 
   1286         public K getKey() {
   1287             return key;
   1288         }
   1289 
   1290         public V getValue() {
   1291             return value;
   1292         }
   1293 
   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 
   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 
   1312         public int hashCode() {
   1313             return hash ^ Objects.hashCode(value);
   1314         }
   1315 
   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 
   1353         Enumerator(int type, boolean iterator) {
   1354             this.type = type;
   1355             this.iterator = iterator;
   1356         }
   1357 
   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")
   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
   1391         public boolean hasNext() {
   1392             return hasMoreElements();
   1393         }
   1394 
   1395         public T next() {
   1396             if (modCount != expectedModCount)
   1397                 throw new ConcurrentModificationException();
   1398             return nextElement();
   1399         }
   1400 
   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