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