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