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