HashTable和HashMap

参考自:

http://blog.csdn.net/tgxblue/article/details/8479147 

 

HashMap和HashTable的异同:

1 HashMap是非线程安全的,HashTable线程安全,

2 有了第一点,那么HashMap肯定效率高一些,HashTable要低一些

3 HashMap的键和值都可以是null,HashTable的键和值都不行。

通过HashTable的 

java.util.Hashtable.put(K key, V value)
方法以及HashMap的put(K key,V value)方法就可以看出来HashMap以及HashTable是否是线程安全,
具体如下:
 1 public synchronized V put(K key, V value) {
 2         // Make sure the value is not null
 3         if (value == null) {
 4             throw new NullPointerException();
 5         }
 6 
 7         // Makes sure the key is not already in the hashtable.
 8         Entry<?,?> tab[] = table;
 9         int hash = key.hashCode();
10         int index = (hash & 0x7FFFFFFF) % tab.length;
11         @SuppressWarnings("unchecked")
12         Entry<K,V> entry = (Entry<K,V>)tab[index];
13         for(; entry != null ; entry = entry.next) {
14             if ((entry.hash == hash) && entry.key.equals(key)) {
15                 V old = entry.value;
16                 entry.value = value;
17                 return old;
18             }
19         }
20 
21         addEntry(hash, key, value, index);
22         return null;
23     }

 

HashMap.java的put(K key,V value)方法如下:

 1 /**
 2      * Associates the specified value with the specified key in this map.
 3      * If the map previously contained a mapping for the key, the old
 4      * value is replaced.
 5      *
 6      * @param key key with which the specified value is to be associated
 7      * @param value value to be associated with the specified key
 8      * @return the previous value associated with <tt>key</tt>, or
 9      *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
10      *         (A <tt>null</tt> return can also indicate that the map
11      *         previously associated <tt>null</tt> with <tt>key</tt>.)
12      */
13     public V put(K key, V value) {
14         if (table == EMPTY_TABLE) {
15             inflateTable(threshold);
16         }
17         if (key == null)
18             return putForNullKey(value);
19         int hash = hash(key);
20         int i = indexFor(hash, table.length);
21         for (Entry<K,V> e = table[i]; e != null; e = e.next) {
22             Object k;
23             if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
24                 V oldValue = e.value;
25                 e.value = value;
26                 e.recordAccess(this);
27                 return oldValue;
28             }
29         }
30 
31         modCount++;
32         addEntry(hash, key, value, i);
33         return null;
34     }

 

 

HashTable.java

   1 /*
   2  * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
   4  *
   5  *
   6  *
   7  *
   8  *
   9  *
  10  *
  11  *
  12  *
  13  *
  14  *
  15  *
  16  *
  17  *
  18  *
  19  *
  20  *
  21  *
  22  *
  23  *
  24  */
  25 
  26 package java.util;
  27 
  28 import java.io.*;
  29 import java.util.concurrent.ThreadLocalRandom;
  30 import java.util.function.BiConsumer;
  31 import java.util.function.Function;
  32 import java.util.function.BiFunction;
  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}/../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 Entry<?,?>[] 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 Entry<?,?>[initialCapacity];
 191         threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
 192     }
 193 
 194     /**
 195      * Constructs a new, empty hashtable with the specified initial capacity
 196      * and default load factor (0.75).
 197      *
 198      * @param     initialCapacity   the initial capacity of the hashtable.
 199      * @exception IllegalArgumentException if the initial capacity is less
 200      *              than zero.
 201      */
 202     public Hashtable(int initialCapacity) {
 203         this(initialCapacity, 0.75f);
 204     }
 205 
 206     /**
 207      * Constructs a new, empty hashtable with a default initial capacity (11)
 208      * and load factor (0.75).
 209      */
 210     public Hashtable() {
 211         this(11, 0.75f);
 212     }
 213 
 214     /**
 215      * Constructs a new hashtable with the same mappings as the given
 216      * Map.  The hashtable is created with an initial capacity sufficient to
 217      * hold the mappings in the given Map and a default load factor (0.75).
 218      *
 219      * @param t the map whose mappings are to be placed in this map.
 220      * @throws NullPointerException if the specified map is null.
 221      * @since   1.2
 222      */
 223     public Hashtable(Map<? extends K, ? extends V> t) {
 224         this(Math.max(2*t.size(), 11), 0.75f);
 225         putAll(t);
 226     }
 227 
 228     /**
 229      * Returns the number of keys in this hashtable.
 230      *
 231      * @return  the number of keys in this hashtable.
 232      */
 233     public synchronized int size() {
 234         return count;
 235     }
 236 
 237     /**
 238      * Tests if this hashtable maps no keys to values.
 239      *
 240      * @return  <code>true</code> if this hashtable maps no keys to values;
 241      *          <code>false</code> otherwise.
 242      */
 243     public synchronized boolean isEmpty() {
 244         return count == 0;
 245     }
 246 
 247     /**
 248      * Returns an enumeration of the keys in this hashtable.
 249      *
 250      * @return  an enumeration of the keys in this hashtable.
 251      * @see     Enumeration
 252      * @see     #elements()
 253      * @see     #keySet()
 254      * @see     Map
 255      */
 256     public synchronized Enumeration<K> keys() {
 257         return this.<K>getEnumeration(KEYS);
 258     }
 259 
 260     /**
 261      * Returns an enumeration of the values in this hashtable.
 262      * Use the Enumeration methods on the returned object to fetch the elements
 263      * sequentially.
 264      *
 265      * @return  an enumeration of the values in this hashtable.
 266      * @see     java.util.Enumeration
 267      * @see     #keys()
 268      * @see     #values()
 269      * @see     Map
 270      */
 271     public synchronized Enumeration<V> elements() {
 272         return this.<V>getEnumeration(VALUES);
 273     }
 274 
 275     /**
 276      * Tests if some key maps into the specified value in this hashtable.
 277      * This operation is more expensive than the {@link #containsKey
 278      * containsKey} method.
 279      *
 280      * <p>Note that this method is identical in functionality to
 281      * {@link #containsValue containsValue}, (which is part of the
 282      * {@link Map} interface in the collections framework).
 283      *
 284      * @param      value   a value to search for
 285      * @return     <code>true</code> if and only if some key maps to the
 286      *             <code>value</code> argument in this hashtable as
 287      *             determined by the <tt>equals</tt> method;
 288      *             <code>false</code> otherwise.
 289      * @exception  NullPointerException  if the value is <code>null</code>
 290      */
 291     public synchronized boolean contains(Object value) {
 292         if (value == null) {
 293             throw new NullPointerException();
 294         }
 295 
 296         Entry<?,?> tab[] = table;
 297         for (int i = tab.length ; i-- > 0 ;) {
 298             for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
 299                 if (e.value.equals(value)) {
 300                     return true;
 301                 }
 302             }
 303         }
 304         return false;
 305     }
 306 
 307     /**
 308      * Returns true if this hashtable maps one or more keys to this value.
 309      *
 310      * <p>Note that this method is identical in functionality to {@link
 311      * #contains contains} (which predates the {@link Map} interface).
 312      *
 313      * @param value value whose presence in this hashtable is to be tested
 314      * @return <tt>true</tt> if this map maps one or more keys to the
 315      *         specified value
 316      * @throws NullPointerException  if the value is <code>null</code>
 317      * @since 1.2
 318      */
 319     public boolean containsValue(Object value) {
 320         return contains(value);
 321     }
 322 
 323     /**
 324      * Tests if the specified object is a key in this hashtable.
 325      *
 326      * @param   key   possible key
 327      * @return  <code>true</code> if and only if the specified object
 328      *          is a key in this hashtable, as determined by the
 329      *          <tt>equals</tt> method; <code>false</code> otherwise.
 330      * @throws  NullPointerException  if the key is <code>null</code>
 331      * @see     #contains(Object)
 332      */
 333     public synchronized boolean containsKey(Object key) {
 334         Entry<?,?> tab[] = table;
 335         int hash = key.hashCode();
 336         int index = (hash & 0x7FFFFFFF) % tab.length;
 337         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
 338             if ((e.hash == hash) && e.key.equals(key)) {
 339                 return true;
 340             }
 341         }
 342         return false;
 343     }
 344 
 345     /**
 346      * Returns the value to which the specified key is mapped,
 347      * or {@code null} if this map contains no mapping for the key.
 348      *
 349      * <p>More formally, if this map contains a mapping from a key
 350      * {@code k} to a value {@code v} such that {@code (key.equals(k))},
 351      * then this method returns {@code v}; otherwise it returns
 352      * {@code null}.  (There can be at most one such mapping.)
 353      *
 354      * @param key the key whose associated value is to be returned
 355      * @return the value to which the specified key is mapped, or
 356      *         {@code null} if this map contains no mapping for the key
 357      * @throws NullPointerException if the specified key is null
 358      * @see     #put(Object, Object)
 359      */
 360     @SuppressWarnings("unchecked")
 361     public synchronized V get(Object key) {
 362         Entry<?,?> tab[] = table;
 363         int hash = key.hashCode();
 364         int index = (hash & 0x7FFFFFFF) % tab.length;
 365         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
 366             if ((e.hash == hash) && e.key.equals(key)) {
 367                 return (V)e.value;
 368             }
 369         }
 370         return null;
 371     }
 372 
 373     /**
 374      * The maximum size of array to allocate.
 375      * Some VMs reserve some header words in an array.
 376      * Attempts to allocate larger arrays may result in
 377      * OutOfMemoryError: Requested array size exceeds VM limit
 378      */
 379     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 380 
 381     /**
 382      * Increases the capacity of and internally reorganizes this
 383      * hashtable, in order to accommodate and access its entries more
 384      * efficiently.  This method is called automatically when the
 385      * number of keys in the hashtable exceeds this hashtable's capacity
 386      * and load factor.
 387      */
 388     @SuppressWarnings("unchecked")
 389     protected void rehash() {
 390         int oldCapacity = table.length;
 391         Entry<?,?>[] oldMap = table;
 392 
 393         // overflow-conscious code
 394         int newCapacity = (oldCapacity << 1) + 1;
 395         if (newCapacity - MAX_ARRAY_SIZE > 0) {
 396             if (oldCapacity == MAX_ARRAY_SIZE)
 397                 // Keep running with MAX_ARRAY_SIZE buckets
 398                 return;
 399             newCapacity = MAX_ARRAY_SIZE;
 400         }
 401         Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
 402 
 403         modCount++;
 404         threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
 405         table = newMap;
 406 
 407         for (int i = oldCapacity ; i-- > 0 ;) {
 408             for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
 409                 Entry<K,V> e = old;
 410                 old = old.next;
 411 
 412                 int index = (e.hash & 0x7FFFFFFF) % newCapacity;
 413                 e.next = (Entry<K,V>)newMap[index];
 414                 newMap[index] = e;
 415             }
 416         }
 417     }
 418 
 419     private void addEntry(int hash, K key, V value, int index) {
 420         modCount++;
 421 
 422         Entry<?,?> tab[] = table;
 423         if (count >= threshold) {
 424             // Rehash the table if the threshold is exceeded
 425             rehash();
 426 
 427             tab = table;
 428             hash = key.hashCode();
 429             index = (hash & 0x7FFFFFFF) % tab.length;
 430         }
 431 
 432         // Creates the new entry.
 433         @SuppressWarnings("unchecked")
 434         Entry<K,V> e = (Entry<K,V>) tab[index];
 435         tab[index] = new Entry<>(hash, key, value, e);
 436         count++;
 437     }
 438 
 439     /**
 440      * Maps the specified <code>key</code> to the specified
 441      * <code>value</code> in this hashtable. Neither the key nor the
 442      * value can be <code>null</code>. <p>
 443      *
 444      * The value can be retrieved by calling the <code>get</code> method
 445      * with a key that is equal to the original key.
 446      *
 447      * @param      key     the hashtable key
 448      * @param      value   the value
 449      * @return     the previous value of the specified key in this hashtable,
 450      *             or <code>null</code> if it did not have one
 451      * @exception  NullPointerException  if the key or value is
 452      *               <code>null</code>
 453      * @see     Object#equals(Object)
 454      * @see     #get(Object)
 455      */
 456     public synchronized V put(K key, V value) {
 457         // Make sure the value is not null
 458         // 如果 value是null,那么就抛出空指针异常,20170407,wyl
 459         if (value == null) {
 460             throw new NullPointerException();
 461         }
 462 
 463         // Makes sure the key is not already in the hashtable.
 464         Entry<?,?> tab[] = table;
 465         // 如果 key 是null,那么在调用hashCode()方法的时候也会抛出空指针异常,20170407,wyl
 466         int hash = key.hashCode();
 467         int index = (hash & 0x7FFFFFFF) % tab.length;
 468         @SuppressWarnings("unchecked")
 469         Entry<K,V> entry = (Entry<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         Entry<?,?> tab[] = table;
 493         int hash = key.hashCode();
 494         int index = (hash & 0x7FFFFFFF) % tab.length;
 495         @SuppressWarnings("unchecked")
 496         Entry<K,V> e = (Entry<K,V>)tab[index];
 497         for(Entry<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         Entry<?,?> 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 Entry<?,?>[table.length];
 550             for (int i = table.length ; i-- > 0 ; ) {
 551                 t.table[i] = (table[i] != null)
 552                     ? (Entry<?,?>) 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             Entry<?,?>[] tab = table;
 702             int hash = key.hashCode();
 703             int index = (hash & 0x7FFFFFFF) % tab.length;
 704 
 705             for (Entry<?,?> 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             Entry<?,?>[] tab = table;
 717             int hash = key.hashCode();
 718             int index = (hash & 0x7FFFFFFF) % tab.length;
 719 
 720             @SuppressWarnings("unchecked")
 721             Entry<K,V> e = (Entry<K,V>)tab[index];
 722             for(Entry<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         Entry<?,?>[] tab = table;
 852         for (Entry<?,?> 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         Entry<?, ?>[] tab = table;
 878         for (Entry<?, ?> 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         Entry<K, V>[] tab = (Entry<K, V>[])table;
 898         for (Entry<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         Entry<?,?> tab[] = table;
 917         int hash = key.hashCode();
 918         int index = (hash & 0x7FFFFFFF) % tab.length;
 919         @SuppressWarnings("unchecked")
 920         Entry<K,V> entry = (Entry<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         Entry<?,?> tab[] = table;
 940         int hash = key.hashCode();
 941         int index = (hash & 0x7FFFFFFF) % tab.length;
 942         @SuppressWarnings("unchecked")
 943         Entry<K,V> e = (Entry<K,V>)tab[index];
 944         for (Entry<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         Entry<?,?> tab[] = table;
 965         int hash = key.hashCode();
 966         int index = (hash & 0x7FFFFFFF) % tab.length;
 967         @SuppressWarnings("unchecked")
 968         Entry<K,V> e = (Entry<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         Entry<?,?> tab[] = table;
 986         int hash = key.hashCode();
 987         int index = (hash & 0x7FFFFFFF) % tab.length;
 988         @SuppressWarnings("unchecked")
 989         Entry<K,V> e = (Entry<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         Entry<?,?> tab[] = table;
1005         int hash = key.hashCode();
1006         int index = (hash & 0x7FFFFFFF) % tab.length;
1007         @SuppressWarnings("unchecked")
1008         Entry<K,V> e = (Entry<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         Entry<?,?> tab[] = table;
1029         int hash = key.hashCode();
1030         int index = (hash & 0x7FFFFFFF) % tab.length;
1031         @SuppressWarnings("unchecked")
1032         Entry<K,V> e = (Entry<K,V>)tab[index];
1033         for (Entry<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         Entry<?,?> tab[] = table;
1058         int hash = key.hashCode();
1059         int index = (hash & 0x7FFFFFFF) % tab.length;
1060         @SuppressWarnings("unchecked")
1061         Entry<K,V> e = (Entry<K,V>)tab[index];
1062         for (Entry<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         Entry<?,?> tab[] = table;
1093         int hash = key.hashCode();
1094         int index = (hash & 0x7FFFFFFF) % tab.length;
1095         @SuppressWarnings("unchecked")
1096         Entry<K,V> e = (Entry<K,V>)tab[index];
1097         for (Entry<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         Entry<Object, Object> entryStack = null;
1135 
1136         synchronized (this) {
1137             // Write out the length, threshold, loadfactor
1138             s.defaultWriteObject();
1139 
1140             // Write out length, 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                 Entry<?,?> entry = table[index];
1147 
1148                 while (entry != null) {
1149                     entryStack =
1150                         new Entry<>(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 length, threshold, and loadfactor
1171         s.defaultReadObject();
1172 
1173         // Read the original length of the array and number of elements
1174         int origlength = s.readInt();
1175         int elements = s.readInt();
1176 
1177         // Compute new size with a bit of room 5% to grow but
1178         // no larger than the original size.  Make the length
1179         // odd if it's large enough, this helps distribute the entries.
1180         // Guard against the length ending up zero, that's not valid.
1181         int length = (int)(elements * loadFactor) + (elements / 20) + 3;
1182         if (length > elements && (length & 1) == 0)
1183             length--;
1184         if (origlength > 0 && length > origlength)
1185             length = origlength;
1186         table = new Entry<?,?>[length];
1187         threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
1188         count = 0;
1189 
1190         // Read the number of elements and then all the key/value objects
1191         for (; elements > 0; elements--) {
1192             @SuppressWarnings("unchecked")
1193                 K key = (K)s.readObject();
1194             @SuppressWarnings("unchecked")
1195                 V value = (V)s.readObject();
1196             // synch could be eliminated for performance
1197             reconstitutionPut(table, key, value);
1198         }
1199     }
1200 
1201     /**
1202      * The put method used by readObject. This is provided because put
1203      * is overridable and should not be called in readObject since the
1204      * subclass will not yet be initialized.
1205      *
1206      * <p>This differs from the regular put method in several ways. No
1207      * checking for rehashing is necessary since the number of elements
1208      * initially in the table is known. The modCount is not incremented
1209      * because we are creating a new instance. Also, no return value
1210      * is needed.
1211      */
1212     private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
1213         throws StreamCorruptedException
1214     {
1215         if (value == null) {
1216             throw new java.io.StreamCorruptedException();
1217         }
1218         // Makes sure the key is not already in the hashtable.
1219         // This should not happen in deserialized version.
1220         int hash = key.hashCode();
1221         int index = (hash & 0x7FFFFFFF) % tab.length;
1222         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
1223             if ((e.hash == hash) && e.key.equals(key)) {
1224                 throw new java.io.StreamCorruptedException();
1225             }
1226         }
1227         // Creates the new entry.
1228         @SuppressWarnings("unchecked")
1229             Entry<K,V> e = (Entry<K,V>)tab[index];
1230         tab[index] = new Entry<>(hash, key, value, e);
1231         count++;
1232     }
1233 
1234     /**
1235      * Hashtable bucket collision list entry
1236      */
1237     private static class Entry<K,V> implements Map.Entry<K,V> {
1238         final int hash;
1239         final K key;
1240         V value;
1241         Entry<K,V> next;
1242 
1243         protected Entry(int hash, K key, V value, Entry<K,V> next) {
1244             this.hash = hash;
1245             this.key =  key;
1246             this.value = value;
1247             this.next = next;
1248         }
1249 
1250         @SuppressWarnings("unchecked")
1251         protected Object clone() {
1252             return new Entry<>(hash, key, value,
1253                                   (next==null ? null : (Entry<K,V>) next.clone()));
1254         }
1255 
1256         // Map.Entry Ops
1257 
1258         public K getKey() {
1259             return key;
1260         }
1261 
1262         public V getValue() {
1263             return value;
1264         }
1265 
1266         public V setValue(V value) {
1267             if (value == null)
1268                 throw new NullPointerException();
1269 
1270             V oldValue = this.value;
1271             this.value = value;
1272             return oldValue;
1273         }
1274 
1275         public boolean equals(Object o) {
1276             if (!(o instanceof Map.Entry))
1277                 return false;
1278             Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1279 
1280             return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
1281                (value==null ? e.getValue()==null : value.equals(e.getValue()));
1282         }
1283 
1284         public int hashCode() {
1285             return hash ^ Objects.hashCode(value);
1286         }
1287 
1288         public String toString() {
1289             return key.toString()+"="+value.toString();
1290         }
1291     }
1292 
1293     // Types of Enumerations/Iterations
1294     private static final int KEYS = 0;
1295     private static final int VALUES = 1;
1296     private static final int ENTRIES = 2;
1297 
1298     /**
1299      * A hashtable enumerator class.  This class implements both the
1300      * Enumeration and Iterator interfaces, but individual instances
1301      * can be created with the Iterator methods disabled.  This is necessary
1302      * to avoid unintentionally increasing the capabilities granted a user
1303      * by passing an Enumeration.
1304      */
1305     private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
1306         Entry<?,?>[] table = Hashtable.this.table;
1307         int index = table.length;
1308         Entry<?,?> entry;
1309         Entry<?,?> lastReturned;
1310         int type;
1311 
1312         /**
1313          * Indicates whether this Enumerator is serving as an Iterator
1314          * or an Enumeration.  (true -> Iterator).
1315          */
1316         boolean iterator;
1317 
1318         /**
1319          * The modCount value that the iterator believes that the backing
1320          * Hashtable should have.  If this expectation is violated, the iterator
1321          * has detected concurrent modification.
1322          */
1323         protected int expectedModCount = modCount;
1324 
1325         Enumerator(int type, boolean iterator) {
1326             this.type = type;
1327             this.iterator = iterator;
1328         }
1329 
1330         public boolean hasMoreElements() {
1331             Entry<?,?> e = entry;
1332             int i = index;
1333             Entry<?,?>[] t = table;
1334             /* Use locals for faster loop iteration */
1335             while (e == null && i > 0) {
1336                 e = t[--i];
1337             }
1338             entry = e;
1339             index = i;
1340             return e != null;
1341         }
1342 
1343         @SuppressWarnings("unchecked")
1344         public T nextElement() {
1345             Entry<?,?> et = entry;
1346             int i = index;
1347             Entry<?,?>[] t = table;
1348             /* Use locals for faster loop iteration */
1349             while (et == null && i > 0) {
1350                 et = t[--i];
1351             }
1352             entry = et;
1353             index = i;
1354             if (et != null) {
1355                 Entry<?,?> e = lastReturned = entry;
1356                 entry = e.next;
1357                 return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
1358             }
1359             throw new NoSuchElementException("Hashtable Enumerator");
1360         }
1361 
1362         // Iterator methods
1363         public boolean hasNext() {
1364             return hasMoreElements();
1365         }
1366 
1367         public T next() {
1368             if (modCount != expectedModCount)
1369                 throw new ConcurrentModificationException();
1370             return nextElement();
1371         }
1372 
1373         public void remove() {
1374             if (!iterator)
1375                 throw new UnsupportedOperationException();
1376             if (lastReturned == null)
1377                 throw new IllegalStateException("Hashtable Enumerator");
1378             if (modCount != expectedModCount)
1379                 throw new ConcurrentModificationException();
1380 
1381             synchronized(Hashtable.this) {
1382                 Entry<?,?>[] tab = Hashtable.this.table;
1383                 int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
1384 
1385                 @SuppressWarnings("unchecked")
1386                 Entry<K,V> e = (Entry<K,V>)tab[index];
1387                 for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
1388                     if (e == lastReturned) {
1389                         modCount++;
1390                         expectedModCount++;
1391                         if (prev == null)
1392                             tab[index] = e.next;
1393                         else
1394                             prev.next = e.next;
1395                         count--;
1396                         lastReturned = null;
1397                         return;
1398                     }
1399                 }
1400                 throw new ConcurrentModificationException();
1401             }
1402         }
1403     }
1404 }

 

posted @ 2017-04-07 14:46  Sunor  阅读(251)  评论(0编辑  收藏  举报