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