• 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 }
  • 相关阅读:
    创建你的一个composer包
    git 命令添加整个文件夹以及文件夹下的内容
    Svn在工作中的实践感悟
    Ubuntu17.04 sudo apt-get update升级错误
    Ubuntu composer 安装thinkphp5 失败,报错:[ErrorException] mkdir(): Permission denied
    2017年总结与展望
    Html 解决数字和字母不换行
    Github上html页面(包括CSS样式和JS效果)如何显示出来
    Ubuntu下crontab启动、重启、关闭命令
    ubuntu14.04 安装 php Composer时 composer:未找到命令
  • 原文地址:https://www.cnblogs.com/Sunnor/p/6678056.html
Copyright © 2020-2023  润新知