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