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