Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/util/Hashtable.java
38829 views
/*1* Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.util;2627import java.io.*;28import java.util.concurrent.ThreadLocalRandom;29import java.util.function.BiConsumer;30import java.util.function.Function;31import java.util.function.BiFunction;32import sun.misc.SharedSecrets;3334/**35* This class implements a hash table, which maps keys to values. Any36* 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, the39* 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 its43* performance: <i>initial capacity</i> and <i>load factor</i>. The44* <i>capacity</i> is the number of <i>buckets</i> in the hash table, and the45* <i>initial capacity</i> is simply the capacity at the time the hash table46* is created. Note that the hash table is <i>open</i>: in the case of a "hash47* collision", a single bucket stores multiple entries, which must be searched48* sequentially. The <i>load factor</i> is a measure of how full the hash49* table is allowed to get before its capacity is automatically increased.50* The initial capacity and load factor parameters are merely hints to51* the implementation. The exact details as to when and whether the rehash52* method is invoked are implementation-dependent.<p>53*54* Generally, the default load factor (.75) offers a good tradeoff between55* time and space costs. Higher values decrease the space overhead but56* increase the time cost to look up an entry (which is reflected in most57* <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 the60* need for <code>rehash</code> operations, which are time-consuming.61* No <code>rehash</code> operations will <i>ever</i> occur if the initial62* capacity is greater than the maximum number of entries the63* <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 the68* entries to be inserted more efficiently than letting it perform69* automatic rehashing as needed to grow the table. <p>70*71* This example creates a hashtable of numbers. It uses the names of72* the numbers as keys:73* <pre> {@code74* Hashtable<String, Integer> numbers75* = 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> {@code82* 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 collections88* returned by all of this class's "collection view methods" are89* <em>fail-fast</em>: if the Hashtable is structurally modified at any time90* after the iterator is created, in any way except through the iterator's own91* <tt>remove</tt> method, the iterator will throw a {@link92* ConcurrentModificationException}. Thus, in the face of concurrent93* modification, the iterator fails quickly and cleanly, rather than risking94* arbitrary, non-deterministic behavior at an undetermined time in the future.95* The Enumerations returned by Hashtable's keys and elements methods are96* <em>not</em> fail-fast.97*98* <p>Note that the fail-fast behavior of an iterator cannot be guaranteed99* as it is, generally speaking, impossible to make any hard guarantees in the100* presence of unsynchronized concurrent modification. Fail-fast iterators101* throw <tt>ConcurrentModificationException</tt> on a best-effort basis.102* Therefore, it would be wrong to write a program that depended on this103* exception for its correctness: <i>the fail-fast behavior of iterators104* should be used only to detect bugs.</i>105*106* <p>As of the Java 2 platform v1.2, this class was retrofitted to107* implement the {@link Map} interface, making it a member of the108* <a href="{@docRoot}/../technotes/guides/collections/index.html">109*110* Java Collections Framework</a>. Unlike the new collection111* implementations, {@code Hashtable} is synchronized. If a112* thread-safe implementation is not needed, it is recommended to use113* {@link HashMap} in place of {@code Hashtable}. If a thread-safe114* highly-concurrent implementation is desired, then it is recommended115* to use {@link java.util.concurrent.ConcurrentHashMap} in place of116* {@code Hashtable}.117*118* @author Arthur van Hoff119* @author Josh Bloch120* @author Neal Gafter121* @see Object#equals(java.lang.Object)122* @see Object#hashCode()123* @see Hashtable#rehash()124* @see Collection125* @see Map126* @see HashMap127* @see TreeMap128* @since JDK1.0129*/130public class Hashtable<K,V>131extends Dictionary<K,V>132implements Map<K,V>, Cloneable, java.io.Serializable {133134/**135* The hash table data.136*/137private transient Entry<?,?>[] table;138139/**140* The total number of entries in the hash table.141*/142private transient int count;143144/**145* The table is rehashed when its size exceeds this threshold. (The146* value of this field is (int)(capacity * loadFactor).)147*148* @serial149*/150private int threshold;151152/**153* The load factor for the hashtable.154*155* @serial156*/157private float loadFactor;158159/**160* The number of times this Hashtable has been structurally modified161* Structural modifications are those that change the number of entries in162* the Hashtable or otherwise modify its internal structure (e.g.,163* rehash). This field is used to make iterators on Collection-views of164* the Hashtable fail-fast. (See ConcurrentModificationException).165*/166private transient int modCount = 0;167168/** use serialVersionUID from JDK 1.0.2 for interoperability */169private static final long serialVersionUID = 1421746759512286392L;170171/**172* Constructs a new, empty hashtable with the specified initial173* 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 less178* than zero, or if the load factor is nonpositive.179*/180public Hashtable(int initialCapacity, float loadFactor) {181if (initialCapacity < 0)182throw new IllegalArgumentException("Illegal Capacity: "+183initialCapacity);184if (loadFactor <= 0 || Float.isNaN(loadFactor))185throw new IllegalArgumentException("Illegal Load: "+loadFactor);186187if (initialCapacity==0)188initialCapacity = 1;189this.loadFactor = loadFactor;190table = new Entry<?,?>[initialCapacity];191threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);192}193194/**195* Constructs a new, empty hashtable with the specified initial capacity196* and default load factor (0.75).197*198* @param initialCapacity the initial capacity of the hashtable.199* @exception IllegalArgumentException if the initial capacity is less200* than zero.201*/202public Hashtable(int initialCapacity) {203this(initialCapacity, 0.75f);204}205206/**207* Constructs a new, empty hashtable with a default initial capacity (11)208* and load factor (0.75).209*/210public Hashtable() {211this(11, 0.75f);212}213214/**215* Constructs a new hashtable with the same mappings as the given216* Map. The hashtable is created with an initial capacity sufficient to217* 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.2222*/223public Hashtable(Map<? extends K, ? extends V> t) {224this(Math.max(2*t.size(), 11), 0.75f);225putAll(t);226}227228/**229* Returns the number of keys in this hashtable.230*231* @return the number of keys in this hashtable.232*/233public synchronized int size() {234return count;235}236237/**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*/243public synchronized boolean isEmpty() {244return count == 0;245}246247/**248* Returns an enumeration of the keys in this hashtable.249*250* @return an enumeration of the keys in this hashtable.251* @see Enumeration252* @see #elements()253* @see #keySet()254* @see Map255*/256public synchronized Enumeration<K> keys() {257return this.<K>getEnumeration(KEYS);258}259260/**261* Returns an enumeration of the values in this hashtable.262* Use the Enumeration methods on the returned object to fetch the elements263* sequentially.264*265* @return an enumeration of the values in this hashtable.266* @see java.util.Enumeration267* @see #keys()268* @see #values()269* @see Map270*/271public synchronized Enumeration<V> elements() {272return this.<V>getEnumeration(VALUES);273}274275/**276* Tests if some key maps into the specified value in this hashtable.277* This operation is more expensive than the {@link #containsKey278* containsKey} method.279*280* <p>Note that this method is identical in functionality to281* {@link #containsValue containsValue}, (which is part of the282* {@link Map} interface in the collections framework).283*284* @param value a value to search for285* @return <code>true</code> if and only if some key maps to the286* <code>value</code> argument in this hashtable as287* determined by the <tt>equals</tt> method;288* <code>false</code> otherwise.289* @exception NullPointerException if the value is <code>null</code>290*/291public synchronized boolean contains(Object value) {292if (value == null) {293throw new NullPointerException();294}295296Entry<?,?> tab[] = table;297for (int i = tab.length ; i-- > 0 ;) {298for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {299if (e.value.equals(value)) {300return true;301}302}303}304return false;305}306307/**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 {@link311* #contains contains} (which predates the {@link Map} interface).312*313* @param value value whose presence in this hashtable is to be tested314* @return <tt>true</tt> if this map maps one or more keys to the315* specified value316* @throws NullPointerException if the value is <code>null</code>317* @since 1.2318*/319public boolean containsValue(Object value) {320return contains(value);321}322323/**324* Tests if the specified object is a key in this hashtable.325*326* @param key possible key327* @return <code>true</code> if and only if the specified object328* is a key in this hashtable, as determined by the329* <tt>equals</tt> method; <code>false</code> otherwise.330* @throws NullPointerException if the key is <code>null</code>331* @see #contains(Object)332*/333public synchronized boolean containsKey(Object key) {334Entry<?,?> tab[] = table;335int hash = key.hashCode();336int index = (hash & 0x7FFFFFFF) % tab.length;337for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {338if ((e.hash == hash) && e.key.equals(key)) {339return true;340}341}342return false;343}344345/**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 key350* {@code k} to a value {@code v} such that {@code (key.equals(k))},351* then this method returns {@code v}; otherwise it returns352* {@code null}. (There can be at most one such mapping.)353*354* @param key the key whose associated value is to be returned355* @return the value to which the specified key is mapped, or356* {@code null} if this map contains no mapping for the key357* @throws NullPointerException if the specified key is null358* @see #put(Object, Object)359*/360@SuppressWarnings("unchecked")361public synchronized V get(Object key) {362Entry<?,?> tab[] = table;363int hash = key.hashCode();364int index = (hash & 0x7FFFFFFF) % tab.length;365for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {366if ((e.hash == hash) && e.key.equals(key)) {367return (V)e.value;368}369}370return null;371}372373/**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 in377* OutOfMemoryError: Requested array size exceeds VM limit378*/379private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;380381/**382* Increases the capacity of and internally reorganizes this383* hashtable, in order to accommodate and access its entries more384* efficiently. This method is called automatically when the385* number of keys in the hashtable exceeds this hashtable's capacity386* and load factor.387*/388@SuppressWarnings("unchecked")389protected void rehash() {390int oldCapacity = table.length;391Entry<?,?>[] oldMap = table;392393// overflow-conscious code394int newCapacity = (oldCapacity << 1) + 1;395if (newCapacity - MAX_ARRAY_SIZE > 0) {396if (oldCapacity == MAX_ARRAY_SIZE)397// Keep running with MAX_ARRAY_SIZE buckets398return;399newCapacity = MAX_ARRAY_SIZE;400}401Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];402403modCount++;404threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);405table = newMap;406407for (int i = oldCapacity ; i-- > 0 ;) {408for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {409Entry<K,V> e = old;410old = old.next;411412int index = (e.hash & 0x7FFFFFFF) % newCapacity;413e.next = (Entry<K,V>)newMap[index];414newMap[index] = e;415}416}417}418419private void addEntry(int hash, K key, V value, int index) {420modCount++;421422Entry<?,?> tab[] = table;423if (count >= threshold) {424// Rehash the table if the threshold is exceeded425rehash();426427tab = table;428hash = key.hashCode();429index = (hash & 0x7FFFFFFF) % tab.length;430}431432// Creates the new entry.433@SuppressWarnings("unchecked")434Entry<K,V> e = (Entry<K,V>) tab[index];435tab[index] = new Entry<>(hash, key, value, e);436count++;437}438439/**440* Maps the specified <code>key</code> to the specified441* <code>value</code> in this hashtable. Neither the key nor the442* value can be <code>null</code>. <p>443*444* The value can be retrieved by calling the <code>get</code> method445* with a key that is equal to the original key.446*447* @param key the hashtable key448* @param value the value449* @return the previous value of the specified key in this hashtable,450* or <code>null</code> if it did not have one451* @exception NullPointerException if the key or value is452* <code>null</code>453* @see Object#equals(Object)454* @see #get(Object)455*/456public synchronized V put(K key, V value) {457// Make sure the value is not null458if (value == null) {459throw new NullPointerException();460}461462// Makes sure the key is not already in the hashtable.463Entry<?,?> tab[] = table;464int hash = key.hashCode();465int index = (hash & 0x7FFFFFFF) % tab.length;466@SuppressWarnings("unchecked")467Entry<K,V> entry = (Entry<K,V>)tab[index];468for(; entry != null ; entry = entry.next) {469if ((entry.hash == hash) && entry.key.equals(key)) {470V old = entry.value;471entry.value = value;472return old;473}474}475476addEntry(hash, key, value, index);477return null;478}479480/**481* Removes the key (and its corresponding value) from this482* hashtable. This method does nothing if the key is not in the hashtable.483*484* @param key the key that needs to be removed485* @return the value to which the key had been mapped in this hashtable,486* or <code>null</code> if the key did not have a mapping487* @throws NullPointerException if the key is <code>null</code>488*/489public synchronized V remove(Object key) {490Entry<?,?> tab[] = table;491int hash = key.hashCode();492int index = (hash & 0x7FFFFFFF) % tab.length;493@SuppressWarnings("unchecked")494Entry<K,V> e = (Entry<K,V>)tab[index];495for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {496if ((e.hash == hash) && e.key.equals(key)) {497modCount++;498if (prev != null) {499prev.next = e.next;500} else {501tab[index] = e.next;502}503count--;504V oldValue = e.value;505e.value = null;506return oldValue;507}508}509return null;510}511512/**513* Copies all of the mappings from the specified map to this hashtable.514* These mappings will replace any mappings that this hashtable had for any515* of the keys currently in the specified map.516*517* @param t mappings to be stored in this map518* @throws NullPointerException if the specified map is null519* @since 1.2520*/521public synchronized void putAll(Map<? extends K, ? extends V> t) {522for (Map.Entry<? extends K, ? extends V> e : t.entrySet())523put(e.getKey(), e.getValue());524}525526/**527* Clears this hashtable so that it contains no keys.528*/529public synchronized void clear() {530Entry<?,?> tab[] = table;531modCount++;532for (int index = tab.length; --index >= 0; )533tab[index] = null;534count = 0;535}536537/**538* Creates a shallow copy of this hashtable. All the structure of the539* hashtable itself is copied, but the keys and values are not cloned.540* This is a relatively expensive operation.541*542* @return a clone of the hashtable543*/544public synchronized Object clone() {545try {546Hashtable<?,?> t = (Hashtable<?,?>)super.clone();547t.table = new Entry<?,?>[table.length];548for (int i = table.length ; i-- > 0 ; ) {549t.table[i] = (table[i] != null)550? (Entry<?,?>) table[i].clone() : null;551}552t.keySet = null;553t.entrySet = null;554t.values = null;555t.modCount = 0;556return t;557} catch (CloneNotSupportedException e) {558// this shouldn't happen, since we are Cloneable559throw new InternalError(e);560}561}562563/**564* Returns a string representation of this <tt>Hashtable</tt> object565* in the form of a set of entries, enclosed in braces and separated566* by the ASCII characters "<tt>, </tt>" (comma and space). Each567* entry is rendered as the key, an equals sign <tt>=</tt>, and the568* associated element, where the <tt>toString</tt> method is used to569* convert the key and element to strings.570*571* @return a string representation of this hashtable572*/573public synchronized String toString() {574int max = size() - 1;575if (max == -1)576return "{}";577578StringBuilder sb = new StringBuilder();579Iterator<Map.Entry<K,V>> it = entrySet().iterator();580581sb.append('{');582for (int i = 0; ; i++) {583Map.Entry<K,V> e = it.next();584K key = e.getKey();585V value = e.getValue();586sb.append(key == this ? "(this Map)" : key.toString());587sb.append('=');588sb.append(value == this ? "(this Map)" : value.toString());589590if (i == max)591return sb.append('}').toString();592sb.append(", ");593}594}595596597private <T> Enumeration<T> getEnumeration(int type) {598if (count == 0) {599return Collections.emptyEnumeration();600} else {601return new Enumerator<>(type, false);602}603}604605private <T> Iterator<T> getIterator(int type) {606if (count == 0) {607return Collections.emptyIterator();608} else {609return new Enumerator<>(type, true);610}611}612613// Views614615/**616* Each of these fields are initialized to contain an instance of the617* appropriate view the first time this view is requested. The views are618* stateless, so there's no reason to create more than one of each.619*/620private transient volatile Set<K> keySet;621private transient volatile Set<Map.Entry<K,V>> entrySet;622private transient volatile Collection<V> values;623624/**625* Returns a {@link Set} view of the keys contained in this map.626* The set is backed by the map, so changes to the map are627* reflected in the set, and vice-versa. If the map is modified628* while an iteration over the set is in progress (except through629* the iterator's own <tt>remove</tt> operation), the results of630* the iteration are undefined. The set supports element removal,631* which removes the corresponding mapping from the map, via the632* <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,633* <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>634* operations. It does not support the <tt>add</tt> or <tt>addAll</tt>635* operations.636*637* @since 1.2638*/639public Set<K> keySet() {640if (keySet == null)641keySet = Collections.synchronizedSet(new KeySet(), this);642return keySet;643}644645private class KeySet extends AbstractSet<K> {646public Iterator<K> iterator() {647return getIterator(KEYS);648}649public int size() {650return count;651}652public boolean contains(Object o) {653return containsKey(o);654}655public boolean remove(Object o) {656return Hashtable.this.remove(o) != null;657}658public void clear() {659Hashtable.this.clear();660}661}662663/**664* Returns a {@link Set} view of the mappings contained in this map.665* The set is backed by the map, so changes to the map are666* reflected in the set, and vice-versa. If the map is modified667* while an iteration over the set is in progress (except through668* the iterator's own <tt>remove</tt> operation, or through the669* <tt>setValue</tt> operation on a map entry returned by the670* iterator) the results of the iteration are undefined. The set671* supports element removal, which removes the corresponding672* mapping from the map, via the <tt>Iterator.remove</tt>,673* <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and674* <tt>clear</tt> operations. It does not support the675* <tt>add</tt> or <tt>addAll</tt> operations.676*677* @since 1.2678*/679public Set<Map.Entry<K,V>> entrySet() {680if (entrySet==null)681entrySet = Collections.synchronizedSet(new EntrySet(), this);682return entrySet;683}684685private class EntrySet extends AbstractSet<Map.Entry<K,V>> {686public Iterator<Map.Entry<K,V>> iterator() {687return getIterator(ENTRIES);688}689690public boolean add(Map.Entry<K,V> o) {691return super.add(o);692}693694public boolean contains(Object o) {695if (!(o instanceof Map.Entry))696return false;697Map.Entry<?,?> entry = (Map.Entry<?,?>)o;698Object key = entry.getKey();699Entry<?,?>[] tab = table;700int hash = key.hashCode();701int index = (hash & 0x7FFFFFFF) % tab.length;702703for (Entry<?,?> e = tab[index]; e != null; e = e.next)704if (e.hash==hash && e.equals(entry))705return true;706return false;707}708709public boolean remove(Object o) {710if (!(o instanceof Map.Entry))711return false;712Map.Entry<?,?> entry = (Map.Entry<?,?>) o;713Object key = entry.getKey();714Entry<?,?>[] tab = table;715int hash = key.hashCode();716int index = (hash & 0x7FFFFFFF) % tab.length;717718@SuppressWarnings("unchecked")719Entry<K,V> e = (Entry<K,V>)tab[index];720for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {721if (e.hash==hash && e.equals(entry)) {722modCount++;723if (prev != null)724prev.next = e.next;725else726tab[index] = e.next;727728count--;729e.value = null;730return true;731}732}733return false;734}735736public int size() {737return count;738}739740public void clear() {741Hashtable.this.clear();742}743}744745/**746* Returns a {@link Collection} view of the values contained in this map.747* The collection is backed by the map, so changes to the map are748* reflected in the collection, and vice-versa. If the map is749* modified while an iteration over the collection is in progress750* (except through the iterator's own <tt>remove</tt> operation),751* the results of the iteration are undefined. The collection752* supports element removal, which removes the corresponding753* mapping from the map, via the <tt>Iterator.remove</tt>,754* <tt>Collection.remove</tt>, <tt>removeAll</tt>,755* <tt>retainAll</tt> and <tt>clear</tt> operations. It does not756* support the <tt>add</tt> or <tt>addAll</tt> operations.757*758* @since 1.2759*/760public Collection<V> values() {761if (values==null)762values = Collections.synchronizedCollection(new ValueCollection(),763this);764return values;765}766767private class ValueCollection extends AbstractCollection<V> {768public Iterator<V> iterator() {769return getIterator(VALUES);770}771public int size() {772return count;773}774public boolean contains(Object o) {775return containsValue(o);776}777public void clear() {778Hashtable.this.clear();779}780}781782// Comparison and hashing783784/**785* Compares the specified Object with this Map for equality,786* as per the definition in the Map interface.787*788* @param o object to be compared for equality with this hashtable789* @return true if the specified Object is equal to this Map790* @see Map#equals(Object)791* @since 1.2792*/793public synchronized boolean equals(Object o) {794if (o == this)795return true;796797if (!(o instanceof Map))798return false;799Map<?,?> t = (Map<?,?>) o;800if (t.size() != size())801return false;802803try {804Iterator<Map.Entry<K,V>> i = entrySet().iterator();805while (i.hasNext()) {806Map.Entry<K,V> e = i.next();807K key = e.getKey();808V value = e.getValue();809if (value == null) {810if (!(t.get(key)==null && t.containsKey(key)))811return false;812} else {813if (!value.equals(t.get(key)))814return false;815}816}817} catch (ClassCastException unused) {818return false;819} catch (NullPointerException unused) {820return false;821}822823return true;824}825826/**827* Returns the hash code value for this Map as per the definition in the828* Map interface.829*830* @see Map#hashCode()831* @since 1.2832*/833public synchronized int hashCode() {834/*835* This code detects the recursion caused by computing the hash code836* of a self-referential hash table and prevents the stack overflow837* that would otherwise result. This allows certain 1.1-era838* applets with self-referential hash tables to work. This code839* abuses the loadFactor field to do double-duty as a hashCode840* in progress flag, so as not to worsen the space performance.841* A negative load factor indicates that hash code computation is842* in progress.843*/844int h = 0;845if (count == 0 || loadFactor < 0)846return h; // Returns zero847848loadFactor = -loadFactor; // Mark hashCode computation in progress849Entry<?,?>[] tab = table;850for (Entry<?,?> entry : tab) {851while (entry != null) {852h += entry.hashCode();853entry = entry.next;854}855}856857loadFactor = -loadFactor; // Mark hashCode computation complete858859return h;860}861862@Override863public synchronized V getOrDefault(Object key, V defaultValue) {864V result = get(key);865return (null == result) ? defaultValue : result;866}867868@SuppressWarnings("unchecked")869@Override870public synchronized void forEach(BiConsumer<? super K, ? super V> action) {871Objects.requireNonNull(action); // explicit check required in case872// table is empty.873final int expectedModCount = modCount;874875Entry<?, ?>[] tab = table;876for (Entry<?, ?> entry : tab) {877while (entry != null) {878action.accept((K)entry.key, (V)entry.value);879entry = entry.next;880881if (expectedModCount != modCount) {882throw new ConcurrentModificationException();883}884}885}886}887888@SuppressWarnings("unchecked")889@Override890public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {891Objects.requireNonNull(function); // explicit check required in case892// table is empty.893final int expectedModCount = modCount;894895Entry<K, V>[] tab = (Entry<K, V>[])table;896for (Entry<K, V> entry : tab) {897while (entry != null) {898entry.value = Objects.requireNonNull(899function.apply(entry.key, entry.value));900entry = entry.next;901902if (expectedModCount != modCount) {903throw new ConcurrentModificationException();904}905}906}907}908909@Override910public synchronized V putIfAbsent(K key, V value) {911Objects.requireNonNull(value);912913// Makes sure the key is not already in the hashtable.914Entry<?,?> tab[] = table;915int hash = key.hashCode();916int index = (hash & 0x7FFFFFFF) % tab.length;917@SuppressWarnings("unchecked")918Entry<K,V> entry = (Entry<K,V>)tab[index];919for (; entry != null; entry = entry.next) {920if ((entry.hash == hash) && entry.key.equals(key)) {921V old = entry.value;922if (old == null) {923entry.value = value;924}925return old;926}927}928929addEntry(hash, key, value, index);930return null;931}932933@Override934public synchronized boolean remove(Object key, Object value) {935Objects.requireNonNull(value);936937Entry<?,?> tab[] = table;938int hash = key.hashCode();939int index = (hash & 0x7FFFFFFF) % tab.length;940@SuppressWarnings("unchecked")941Entry<K,V> e = (Entry<K,V>)tab[index];942for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {943if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {944modCount++;945if (prev != null) {946prev.next = e.next;947} else {948tab[index] = e.next;949}950count--;951e.value = null;952return true;953}954}955return false;956}957958@Override959public synchronized boolean replace(K key, V oldValue, V newValue) {960Objects.requireNonNull(oldValue);961Objects.requireNonNull(newValue);962Entry<?,?> tab[] = table;963int hash = key.hashCode();964int index = (hash & 0x7FFFFFFF) % tab.length;965@SuppressWarnings("unchecked")966Entry<K,V> e = (Entry<K,V>)tab[index];967for (; e != null; e = e.next) {968if ((e.hash == hash) && e.key.equals(key)) {969if (e.value.equals(oldValue)) {970e.value = newValue;971return true;972} else {973return false;974}975}976}977return false;978}979980@Override981public synchronized V replace(K key, V value) {982Objects.requireNonNull(value);983Entry<?,?> tab[] = table;984int hash = key.hashCode();985int index = (hash & 0x7FFFFFFF) % tab.length;986@SuppressWarnings("unchecked")987Entry<K,V> e = (Entry<K,V>)tab[index];988for (; e != null; e = e.next) {989if ((e.hash == hash) && e.key.equals(key)) {990V oldValue = e.value;991e.value = value;992return oldValue;993}994}995return null;996}997998@Override999public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {1000Objects.requireNonNull(mappingFunction);10011002Entry<?,?> tab[] = table;1003int hash = key.hashCode();1004int index = (hash & 0x7FFFFFFF) % tab.length;1005@SuppressWarnings("unchecked")1006Entry<K,V> e = (Entry<K,V>)tab[index];1007for (; e != null; e = e.next) {1008if (e.hash == hash && e.key.equals(key)) {1009// Hashtable not accept null value1010return e.value;1011}1012}10131014V newValue = mappingFunction.apply(key);1015if (newValue != null) {1016addEntry(hash, key, newValue, index);1017}10181019return newValue;1020}10211022@Override1023public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {1024Objects.requireNonNull(remappingFunction);10251026Entry<?,?> tab[] = table;1027int hash = key.hashCode();1028int index = (hash & 0x7FFFFFFF) % tab.length;1029@SuppressWarnings("unchecked")1030Entry<K,V> e = (Entry<K,V>)tab[index];1031for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {1032if (e.hash == hash && e.key.equals(key)) {1033V newValue = remappingFunction.apply(key, e.value);1034if (newValue == null) {1035modCount++;1036if (prev != null) {1037prev.next = e.next;1038} else {1039tab[index] = e.next;1040}1041count--;1042} else {1043e.value = newValue;1044}1045return newValue;1046}1047}1048return null;1049}10501051@Override1052public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {1053Objects.requireNonNull(remappingFunction);10541055Entry<?,?> tab[] = table;1056int hash = key.hashCode();1057int index = (hash & 0x7FFFFFFF) % tab.length;1058@SuppressWarnings("unchecked")1059Entry<K,V> e = (Entry<K,V>)tab[index];1060for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {1061if (e.hash == hash && Objects.equals(e.key, key)) {1062V newValue = remappingFunction.apply(key, e.value);1063if (newValue == null) {1064modCount++;1065if (prev != null) {1066prev.next = e.next;1067} else {1068tab[index] = e.next;1069}1070count--;1071} else {1072e.value = newValue;1073}1074return newValue;1075}1076}10771078V newValue = remappingFunction.apply(key, null);1079if (newValue != null) {1080addEntry(hash, key, newValue, index);1081}10821083return newValue;1084}10851086@Override1087public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {1088Objects.requireNonNull(remappingFunction);10891090Entry<?,?> tab[] = table;1091int hash = key.hashCode();1092int index = (hash & 0x7FFFFFFF) % tab.length;1093@SuppressWarnings("unchecked")1094Entry<K,V> e = (Entry<K,V>)tab[index];1095for (Entry<K,V> prev = null; e != null; prev = e, e = e.next) {1096if (e.hash == hash && e.key.equals(key)) {1097V newValue = remappingFunction.apply(e.value, value);1098if (newValue == null) {1099modCount++;1100if (prev != null) {1101prev.next = e.next;1102} else {1103tab[index] = e.next;1104}1105count--;1106} else {1107e.value = newValue;1108}1109return newValue;1110}1111}11121113if (value != null) {1114addEntry(hash, key, value, index);1115}11161117return value;1118}11191120/**1121* Save the state of the Hashtable to a stream (i.e., serialize it).1122*1123* @serialData The <i>capacity</i> of the Hashtable (the length of the1124* bucket array) is emitted (int), followed by the1125* <i>size</i> of the Hashtable (the number of key-value1126* mappings), followed by the key (Object) and value (Object)1127* for each key-value mapping represented by the Hashtable1128* The key-value mappings are emitted in no particular order.1129*/1130private void writeObject(java.io.ObjectOutputStream s)1131throws IOException {1132Entry<Object, Object> entryStack = null;11331134synchronized (this) {1135// Write out the threshold and loadFactor1136s.defaultWriteObject();11371138// Write out the length and count of elements1139s.writeInt(table.length);1140s.writeInt(count);11411142// Stack copies of the entries in the table1143for (int index = 0; index < table.length; index++) {1144Entry<?,?> entry = table[index];11451146while (entry != null) {1147entryStack =1148new Entry<>(0, entry.key, entry.value, entryStack);1149entry = entry.next;1150}1151}1152}11531154// Write out the key/value objects from the stacked entries1155while (entryStack != null) {1156s.writeObject(entryStack.key);1157s.writeObject(entryStack.value);1158entryStack = entryStack.next;1159}1160}11611162/**1163* Reconstitute the Hashtable from a stream (i.e., deserialize it).1164*/1165private void readObject(java.io.ObjectInputStream s)1166throws IOException, ClassNotFoundException1167{1168// Read in the threshold and loadFactor1169s.defaultReadObject();11701171// Validate loadFactor (ignore threshold - it will be re-computed)1172if (loadFactor <= 0 || Float.isNaN(loadFactor))1173throw new StreamCorruptedException("Illegal Load: " + loadFactor);11741175// Read the original length of the array and number of elements1176int origlength = s.readInt();1177int elements = s.readInt();11781179// Validate # of elements1180if (elements < 0)1181throw new StreamCorruptedException("Illegal # of Elements: " + elements);11821183// Clamp original length to be more than elements / loadFactor1184// (this is the invariant enforced with auto-growth)1185origlength = Math.max(origlength, (int)(elements / loadFactor) + 1);11861187// Compute new length with a bit of room 5% + 3 to grow but1188// no larger than the clamped original length. Make the length1189// odd if it's large enough, this helps distribute the entries.1190// Guard against the length ending up zero, that's not valid.1191int length = (int)((elements + elements / 20) / loadFactor) + 3;1192if (length > elements && (length & 1) == 0)1193length--;1194length = Math.min(length, origlength);11951196if (length < 0) { // overflow1197length = origlength;1198}11991200// Check Map.Entry[].class since it's the nearest public type to1201// what we're actually creating.1202SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, length);1203table = new Entry<?,?>[length];1204threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);1205count = 0;12061207// Read the number of elements and then all the key/value objects1208for (; elements > 0; elements--) {1209@SuppressWarnings("unchecked")1210K key = (K)s.readObject();1211@SuppressWarnings("unchecked")1212V value = (V)s.readObject();1213// sync is eliminated for performance1214reconstitutionPut(table, key, value);1215}1216}12171218/**1219* The put method used by readObject. This is provided because put1220* is overridable and should not be called in readObject since the1221* subclass will not yet be initialized.1222*1223* <p>This differs from the regular put method in several ways. No1224* checking for rehashing is necessary since the number of elements1225* initially in the table is known. The modCount is not incremented and1226* there's no synchronization because we are creating a new instance.1227* Also, no return value is needed.1228*/1229private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)1230throws StreamCorruptedException1231{1232if (value == null) {1233throw new java.io.StreamCorruptedException();1234}1235// Makes sure the key is not already in the hashtable.1236// This should not happen in deserialized version.1237int hash = key.hashCode();1238int index = (hash & 0x7FFFFFFF) % tab.length;1239for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {1240if ((e.hash == hash) && e.key.equals(key)) {1241throw new java.io.StreamCorruptedException();1242}1243}1244// Creates the new entry.1245@SuppressWarnings("unchecked")1246Entry<K,V> e = (Entry<K,V>)tab[index];1247tab[index] = new Entry<>(hash, key, value, e);1248count++;1249}12501251/**1252* Hashtable bucket collision list entry1253*/1254private static class Entry<K,V> implements Map.Entry<K,V> {1255final int hash;1256final K key;1257V value;1258Entry<K,V> next;12591260protected Entry(int hash, K key, V value, Entry<K,V> next) {1261this.hash = hash;1262this.key = key;1263this.value = value;1264this.next = next;1265}12661267@SuppressWarnings("unchecked")1268protected Object clone() {1269return new Entry<>(hash, key, value,1270(next==null ? null : (Entry<K,V>) next.clone()));1271}12721273// Map.Entry Ops12741275public K getKey() {1276return key;1277}12781279public V getValue() {1280return value;1281}12821283public V setValue(V value) {1284if (value == null)1285throw new NullPointerException();12861287V oldValue = this.value;1288this.value = value;1289return oldValue;1290}12911292public boolean equals(Object o) {1293if (!(o instanceof Map.Entry))1294return false;1295Map.Entry<?,?> e = (Map.Entry<?,?>)o;12961297return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&1298(value==null ? e.getValue()==null : value.equals(e.getValue()));1299}13001301public int hashCode() {1302return hash ^ Objects.hashCode(value);1303}13041305public String toString() {1306return key.toString()+"="+value.toString();1307}1308}13091310// Types of Enumerations/Iterations1311private static final int KEYS = 0;1312private static final int VALUES = 1;1313private static final int ENTRIES = 2;13141315/**1316* A hashtable enumerator class. This class implements both the1317* Enumeration and Iterator interfaces, but individual instances1318* can be created with the Iterator methods disabled. This is necessary1319* to avoid unintentionally increasing the capabilities granted a user1320* by passing an Enumeration.1321*/1322private class Enumerator<T> implements Enumeration<T>, Iterator<T> {1323Entry<?,?>[] table = Hashtable.this.table;1324int index = table.length;1325Entry<?,?> entry;1326Entry<?,?> lastReturned;1327int type;13281329/**1330* Indicates whether this Enumerator is serving as an Iterator1331* or an Enumeration. (true -> Iterator).1332*/1333boolean iterator;13341335/**1336* The modCount value that the iterator believes that the backing1337* Hashtable should have. If this expectation is violated, the iterator1338* has detected concurrent modification.1339*/1340protected int expectedModCount = modCount;13411342Enumerator(int type, boolean iterator) {1343this.type = type;1344this.iterator = iterator;1345}13461347public boolean hasMoreElements() {1348Entry<?,?> e = entry;1349int i = index;1350Entry<?,?>[] t = table;1351/* Use locals for faster loop iteration */1352while (e == null && i > 0) {1353e = t[--i];1354}1355entry = e;1356index = i;1357return e != null;1358}13591360@SuppressWarnings("unchecked")1361public T nextElement() {1362Entry<?,?> et = entry;1363int i = index;1364Entry<?,?>[] t = table;1365/* Use locals for faster loop iteration */1366while (et == null && i > 0) {1367et = t[--i];1368}1369entry = et;1370index = i;1371if (et != null) {1372Entry<?,?> e = lastReturned = entry;1373entry = e.next;1374return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);1375}1376throw new NoSuchElementException("Hashtable Enumerator");1377}13781379// Iterator methods1380public boolean hasNext() {1381return hasMoreElements();1382}13831384public T next() {1385if (modCount != expectedModCount)1386throw new ConcurrentModificationException();1387return nextElement();1388}13891390public void remove() {1391if (!iterator)1392throw new UnsupportedOperationException();1393if (lastReturned == null)1394throw new IllegalStateException("Hashtable Enumerator");1395if (modCount != expectedModCount)1396throw new ConcurrentModificationException();13971398synchronized(Hashtable.this) {1399Entry<?,?>[] tab = Hashtable.this.table;1400int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;14011402@SuppressWarnings("unchecked")1403Entry<K,V> e = (Entry<K,V>)tab[index];1404for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {1405if (e == lastReturned) {1406modCount++;1407expectedModCount++;1408if (prev == null)1409tab[index] = e.next;1410else1411prev.next = e.next;1412count--;1413lastReturned = null;1414return;1415}1416}1417throw new ConcurrentModificationException();1418}1419}1420}1421}142214231424