标签:resize size cts because opened alter ecif uil nsnull
1 /* 2 * %W% %E% 3 * 4 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. 5 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 6 */ 7 8 package java.util; 9 import java.io.*; 10 11 /** 12 * Hash table based implementation of the <tt>Map</tt> interface. This 13 * implementation provides all of the optional map operations, and permits 14 * <tt>null</tt> values and the <tt>null</tt> key. (The <tt>HashMap</tt> 15 * class is roughly equivalent to <tt>Hashtable</tt>, except that it is 16 * unsynchronized and permits nulls.) This class makes no guarantees as to 17 * the order of the map; in particular, it does not guarantee that the order 18 * will remain constant over time. 19 * 20 * <p>This implementation provides constant-time performance for the basic 21 * operations (<tt>get</tt> and <tt>put</tt>), assuming the hash function 22 * disperses the elements properly among the buckets. Iteration over 23 * collection views requires time proportional to the "capacity" of the 24 * <tt>HashMap</tt> instance (the number of buckets) plus its size (the number 25 * of key-value mappings). Thus, it‘s very important not to set the initial 26 * capacity too high (or the load factor too low) if iteration performance is 27 * important. 28 * 29 * <p>An instance of <tt>HashMap</tt> has two parameters that affect its 30 * performance: <i>initial capacity</i> and <i>load factor</i>. The 31 * <i>capacity</i> is the number of buckets in the hash table, and the initial 32 * capacity is simply the capacity at the time the hash table is created. The 33 * <i>load factor</i> is a measure of how full the hash table is allowed to 34 * get before its capacity is automatically increased. When the number of 35 * entries in the hash table exceeds the product of the load factor and the 36 * current capacity, the hash table is <i>rehashed</i> (that is, internal data 37 * structures are rebuilt) so that the hash table has approximately twice the 38 * number of buckets. 39 * 40 * <p>As a general rule, the default load factor (.75) offers a good tradeoff 41 * between time and space costs. Higher values decrease the space overhead 42 * but increase the lookup cost (reflected in most of the operations of the 43 * <tt>HashMap</tt> class, including <tt>get</tt> and <tt>put</tt>). The 44 * expected number of entries in the map and its load factor should be taken 45 * into account when setting its initial capacity, so as to minimize the 46 * number of rehash operations. If the initial capacity is greater 47 * than the maximum number of entries divided by the load factor, no 48 * rehash operations will ever occur. 49 * 50 * <p>If many mappings are to be stored in a <tt>HashMap</tt> instance, 51 * creating it with a sufficiently large capacity will allow the mappings to 52 * be stored more efficiently than letting it perform automatic rehashing as 53 * needed to grow the table. 54 * 55 * <p><strong>Note that this implementation is not synchronized.</strong> 56 * If multiple threads access a hash map concurrently, and at least one of 57 * the threads modifies the map structurally, it <i>must</i> be 58 * synchronized externally. (A structural modification is any operation 59 * that adds or deletes one or more mappings; merely changing the value 60 * associated with a key that an instance already contains is not a 61 * structural modification.) This is typically accomplished by 62 * synchronizing on some object that naturally encapsulates the map. 63 * 64 * If no such object exists, the map should be "wrapped" using the 65 * {@link Collections#synchronizedMap Collections.synchronizedMap} 66 * method. This is best done at creation time, to prevent accidental 67 * unsynchronized access to the map:<pre> 68 * Map m = Collections.synchronizedMap(new HashMap(...));</pre> 69 * 70 * <p>The iterators returned by all of this class‘s "collection view methods" 71 * are <i>fail-fast</i>: if the map is structurally modified at any time after 72 * the iterator is created, in any way except through the iterator‘s own 73 * <tt>remove</tt> method, the iterator will throw a 74 * {@link ConcurrentModificationException}. Thus, in the face of concurrent 75 * modification, the iterator fails quickly and cleanly, rather than risking 76 * arbitrary, non-deterministic behavior at an undetermined time in the 77 * future. 78 * 79 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed 80 * as it is, generally speaking, impossible to make any hard guarantees in the 81 * presence of unsynchronized concurrent modification. Fail-fast iterators 82 * throw <tt>ConcurrentModificationException</tt> on a best-effort basis. 83 * Therefore, it would be wrong to write a program that depended on this 84 * exception for its correctness: <i>the fail-fast behavior of iterators 85 * should be used only to detect bugs.</i> 86 * 87 * <p>This class is a member of the 88 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 89 * Java Collections Framework</a>. 90 * 91 * @param <K> the type of keys maintained by this map 92 * @param <V> the type of mapped values 93 * 94 * @author Doug Lea 95 * @author Josh Bloch 96 * @author Arthur van Hoff 97 * @author Neal Gafter 98 * @version %I%, %G% 99 * @see Object#hashCode() 100 * @see Collection 101 * @see Map 102 * @see TreeMap 103 * @see Hashtable 104 * @since 1.2 105 */ 106 107 public class HashMap<K,V> 108 extends AbstractMap<K,V> 109 implements Map<K,V>, Cloneable, Serializable 110 { 111 112 /** 113 * The default initial capacity - MUST be a power of two. 114 */ 115 static final int DEFAULT_INITIAL_CAPACITY = 16; 116 117 /** 118 * The maximum capacity, used if a higher value is implicitly specified 119 * by either of the constructors with arguments. 120 * MUST be a power of two <= 1<<30. 121 */ 122 static final int MAXIMUM_CAPACITY = 1 << 30; 123 124 /** 125 * The load factor used when none specified in constructor. 126 */ 127 static final float DEFAULT_LOAD_FACTOR = 0.75f; 128 129 /** 130 * The table, resized as necessary. Length MUST Always be a power of two. 131 */ 132 transient Entry[] table; 133 134 /** 135 * The number of key-value mappings contained in this map. 136 */ 137 transient int size; 138 139 /** 140 * The next size value at which to resize (capacity * load factor). 141 * @serial 142 */ 143 int threshold; 144 145 /** 146 * The load factor for the hash table. 147 * 148 * @serial 149 */ 150 final float loadFactor; 151 152 /** 153 * The number of times this HashMap has been structurally modified 154 * Structural modifications are those that change the number of mappings in 155 * the HashMap or otherwise modify its internal structure (e.g., 156 * rehash). This field is used to make iterators on Collection-views of 157 * the HashMap fail-fast. (See ConcurrentModificationException). 158 */ 159 transient volatile int modCount; 160 161 /** 162 * Constructs an empty <tt>HashMap</tt> with the specified initial 163 * capacity and load factor. 164 * 165 * @param initialCapacity the initial capacity 166 * @param loadFactor the load factor 167 * @throws IllegalArgumentException if the initial capacity is negative 168 * or the load factor is nonpositive 169 */ 170 public HashMap(int initialCapacity, float loadFactor) { 171 if (initialCapacity < 0) 172 throw new IllegalArgumentException("Illegal initial capacity: " + 173 initialCapacity); 174 if (initialCapacity > MAXIMUM_CAPACITY) 175 initialCapacity = MAXIMUM_CAPACITY; 176 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 177 throw new IllegalArgumentException("Illegal load factor: " + 178 loadFactor); 179 180 // Find a power of 2 >= initialCapacity 181 int capacity = 1; 182 while (capacity < initialCapacity) 183 capacity <<= 1; 184 185 this.loadFactor = loadFactor; 186 threshold = (int)(capacity * loadFactor); 187 table = new Entry[capacity]; 188 init(); 189 } 190 191 /** 192 * Constructs an empty <tt>HashMap</tt> with the specified initial 193 * capacity and the default load factor (0.75). 194 * 195 * @param initialCapacity the initial capacity. 196 * @throws IllegalArgumentException if the initial capacity is negative. 197 */ 198 public HashMap(int initialCapacity) { 199 this(initialCapacity, DEFAULT_LOAD_FACTOR); 200 } 201 202 /** 203 * Constructs an empty <tt>HashMap</tt> with the default initial capacity 204 * (16) and the default load factor (0.75). 205 */ 206 public HashMap() { 207 this.loadFactor = DEFAULT_LOAD_FACTOR; 208 threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); 209 table = new Entry[DEFAULT_INITIAL_CAPACITY]; 210 init(); 211 } 212 213 /** 214 * Constructs a new <tt>HashMap</tt> with the same mappings as the 215 * specified <tt>Map</tt>. The <tt>HashMap</tt> is created with 216 * default load factor (0.75) and an initial capacity sufficient to 217 * hold the mappings in the specified <tt>Map</tt>. 218 * 219 * @param m the map whose mappings are to be placed in this map 220 * @throws NullPointerException if the specified map is null 221 */ 222 public HashMap(Map<? extends K, ? extends V> m) { 223 this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, 224 DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); 225 putAllForCreate(m); 226 } 227 228 // internal utilities 229 230 /** 231 * Initialization hook for subclasses. This method is called 232 * in all constructors and pseudo-constructors (clone, readObject) 233 * after HashMap has been initialized but before any entries have 234 * been inserted. (In the absence of this method, readObject would 235 * require explicit knowledge of subclasses.) 236 */ 237 void init() { 238 } 239 240 /** 241 * Applies a supplemental hash function to a given hashCode, which 242 * defends against poor quality hash functions. This is critical 243 * because HashMap uses power-of-two length hash tables, that 244 * otherwise encounter collisions for hashCodes that do not differ 245 * in lower bits. Note: Null keys always map to hash 0, thus index 0. 246 */ 247 static int hash(int h) { 248 // This function ensures that hashCodes that differ only by 249 // constant multiples at each bit position have a bounded 250 // number of collisions (approximately 8 at default load factor). 251 h ^= (h >>> 20) ^ (h >>> 12); 252 return h ^ (h >>> 7) ^ (h >>> 4); 253 } 254 255 /** 256 * Returns index for hash code h. 257 */ 258 static int indexFor(int h, int length) { 259 return h & (length-1); 260 } 261 262 /** 263 * Returns the number of key-value mappings in this map. 264 * 265 * @return the number of key-value mappings in this map 266 */ 267 public int size() { 268 return size; 269 } 270 271 /** 272 * Returns <tt>true</tt> if this map contains no key-value mappings. 273 * 274 * @return <tt>true</tt> if this map contains no key-value mappings 275 */ 276 public boolean isEmpty() { 277 return size == 0; 278 } 279 280 /** 281 * Returns the value to which the specified key is mapped, 282 * or {@code null} if this map contains no mapping for the key. 283 * 284 * <p>More formally, if this map contains a mapping from a key 285 * {@code k} to a value {@code v} such that {@code (key==null ? k==null : 286 * key.equals(k))}, then this method returns {@code v}; otherwise 287 * it returns {@code null}. (There can be at most one such mapping.) 288 * 289 * <p>A return value of {@code null} does not <i>necessarily</i> 290 * indicate that the map contains no mapping for the key; it‘s also 291 * possible that the map explicitly maps the key to {@code null}. 292 * The {@link #containsKey containsKey} operation may be used to 293 * distinguish these two cases. 294 * 295 * @see #put(Object, Object) 296 */ 297 public V get(Object key) { 298 if (key == null) 299 return getForNullKey(); 300 int hash = hash(key.hashCode()); 301 for (Entry<K,V> e = table[indexFor(hash, table.length)]; 302 e != null; 303 e = e.next) { 304 Object k; 305 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) 306 return e.value; 307 } 308 return null; 309 } 310 311 /** 312 * Offloaded version of get() to look up null keys. Null keys map 313 * to index 0. This null case is split out into separate methods 314 * for the sake of performance in the two most commonly used 315 * operations (get and put), but incorporated with conditionals in 316 * others. 317 */ 318 private V getForNullKey() { 319 for (Entry<K,V> e = table[0]; e != null; e = e.next) { 320 if (e.key == null) 321 return e.value; 322 } 323 return null; 324 } 325 326 /** 327 * Returns <tt>true</tt> if this map contains a mapping for the 328 * specified key. 329 * 330 * @param key The key whose presence in this map is to be tested 331 * @return <tt>true</tt> if this map contains a mapping for the specified 332 * key. 333 */ 334 public boolean containsKey(Object key) { 335 return getEntry(key) != null; 336 } 337 338 /** 339 * Returns the entry associated with the specified key in the 340 * HashMap. Returns null if the HashMap contains no mapping 341 * for the key. 342 */ 343 final Entry<K,V> getEntry(Object key) { 344 int hash = (key == null) ? 0 : hash(key.hashCode()); 345 for (Entry<K,V> e = table[indexFor(hash, table.length)]; 346 e != null; 347 e = e.next) { 348 Object k; 349 if (e.hash == hash && 350 ((k = e.key) == key || (key != null && key.equals(k)))) 351 return e; 352 } 353 return null; 354 } 355 356 357 /** 358 * Associates the specified value with the specified key in this map. 359 * If the map previously contained a mapping for the key, the old 360 * value is replaced. 361 * 362 * @param key key with which the specified value is to be associated 363 * @param value value to be associated with the specified key 364 * @return the previous value associated with <tt>key</tt>, or 365 * <tt>null</tt> if there was no mapping for <tt>key</tt>. 366 * (A <tt>null</tt> return can also indicate that the map 367 * previously associated <tt>null</tt> with <tt>key</tt>.) 368 */ 369 public V put(K key, V value) { 370 if (key == null) 371 return putForNullKey(value); 372 int hash = hash(key.hashCode()); 373 int i = indexFor(hash, table.length); 374 for (Entry<K,V> e = table[i]; e != null; e = e.next) { 375 Object k; 376 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 377 V oldValue = e.value; 378 e.value = value; 379 e.recordAccess(this); 380 return oldValue; 381 } 382 } 383 384 modCount++; 385 addEntry(hash, key, value, i); 386 return null; 387 } 388 389 /** 390 * Offloaded version of put for null keys 391 */ 392 private V putForNullKey(V value) { 393 for (Entry<K,V> e = table[0]; e != null; e = e.next) { 394 if (e.key == null) { 395 V oldValue = e.value; 396 e.value = value; 397 e.recordAccess(this); 398 return oldValue; 399 } 400 } 401 modCount++; 402 addEntry(0, null, value, 0); 403 return null; 404 } 405 406 /** 407 * This method is used instead of put by constructors and 408 * pseudoconstructors (clone, readObject). It does not resize the table, 409 * check for comodification, etc. It calls createEntry rather than 410 * addEntry. 411 */ 412 private void putForCreate(K key, V value) { 413 int hash = (key == null) ? 0 : hash(key.hashCode()); 414 int i = indexFor(hash, table.length); 415 416 /** 417 * Look for preexisting entry for key. This will never happen for 418 * clone or deserialize. It will only happen for construction if the 419 * input Map is a sorted map whose ordering is inconsistent w/ equals. 420 */ 421 for (Entry<K,V> e = table[i]; e != null; e = e.next) { 422 Object k; 423 if (e.hash == hash && 424 ((k = e.key) == key || (key != null && key.equals(k)))) { 425 e.value = value; 426 return; 427 } 428 } 429 430 createEntry(hash, key, value, i); 431 } 432 433 private void putAllForCreate(Map<? extends K, ? extends V> m) { 434 for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { 435 Map.Entry<? extends K, ? extends V> e = i.next(); 436 putForCreate(e.getKey(), e.getValue()); 437 } 438 } 439 440 /** 441 * Rehashes the contents of this map into a new array with a 442 * larger capacity. This method is called automatically when the 443 * number of keys in this map reaches its threshold. 444 * 445 * If current capacity is MAXIMUM_CAPACITY, this method does not 446 * resize the map, but sets threshold to Integer.MAX_VALUE. 447 * This has the effect of preventing future calls. 448 * 449 * @param newCapacity the new capacity, MUST be a power of two; 450 * must be greater than current capacity unless current 451 * capacity is MAXIMUM_CAPACITY (in which case value 452 * is irrelevant). 453 */ 454 void resize(int newCapacity) { 455 Entry[] oldTable = table; 456 int oldCapacity = oldTable.length; 457 if (oldCapacity == MAXIMUM_CAPACITY) { 458 threshold = Integer.MAX_VALUE; 459 return; 460 } 461 462 Entry[] newTable = new Entry[newCapacity]; 463 transfer(newTable); 464 table = newTable; 465 threshold = (int)(newCapacity * loadFactor); 466 } 467 468 /** 469 * Transfers all entries from current table to newTable. 470 */ 471 void transfer(Entry[] newTable) { 472 Entry[] src = table; 473 int newCapacity = newTable.length; 474 for (int j = 0; j < src.length; j++) { 475 Entry<K,V> e = src[j]; 476 if (e != null) { 477 src[j] = null; 478 do { 479 Entry<K,V> next = e.next; 480 int i = indexFor(e.hash, newCapacity); 481 e.next = newTable[i]; 482 newTable[i] = e; 483 e = next; 484 } while (e != null); 485 } 486 } 487 } 488 489 /** 490 * Copies all of the mappings from the specified map to this map. 491 * These mappings will replace any mappings that this map had for 492 * any of the keys currently in the specified map. 493 * 494 * @param m mappings to be stored in this map 495 * @throws NullPointerException if the specified map is null 496 */ 497 public void putAll(Map<? extends K, ? extends V> m) { 498 int numKeysToBeAdded = m.size(); 499 if (numKeysToBeAdded == 0) 500 return; 501 502 /* 503 * Expand the map if the map if the number of mappings to be added 504 * is greater than or equal to threshold. This is conservative; the 505 * obvious condition is (m.size() + size) >= threshold, but this 506 * condition could result in a map with twice the appropriate capacity, 507 * if the keys to be added overlap with the keys already in this map. 508 * By using the conservative calculation, we subject ourself 509 * to at most one extra resize. 510 */ 511 if (numKeysToBeAdded > threshold) { 512 int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); 513 if (targetCapacity > MAXIMUM_CAPACITY) 514 targetCapacity = MAXIMUM_CAPACITY; 515 int newCapacity = table.length; 516 while (newCapacity < targetCapacity) 517 newCapacity <<= 1; 518 if (newCapacity > table.length) 519 resize(newCapacity); 520 } 521 522 for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { 523 Map.Entry<? extends K, ? extends V> e = i.next(); 524 put(e.getKey(), e.getValue()); 525 } 526 } 527 528 /** 529 * Removes the mapping for the specified key from this map if present. 530 * 531 * @param key key whose mapping is to be removed from the map 532 * @return the previous value associated with <tt>key</tt>, or 533 * <tt>null</tt> if there was no mapping for <tt>key</tt>. 534 * (A <tt>null</tt> return can also indicate that the map 535 * previously associated <tt>null</tt> with <tt>key</tt>.) 536 */ 537 public V remove(Object key) { 538 Entry<K,V> e = removeEntryForKey(key); 539 return (e == null ? null : e.value); 540 } 541 542 /** 543 * Removes and returns the entry associated with the specified key 544 * in the HashMap. Returns null if the HashMap contains no mapping 545 * for this key. 546 */ 547 final Entry<K,V> removeEntryForKey(Object key) { 548 int hash = (key == null) ? 0 : hash(key.hashCode()); 549 int i = indexFor(hash, table.length); 550 Entry<K,V> prev = table[i]; 551 Entry<K,V> e = prev; 552 553 while (e != null) { 554 Entry<K,V> next = e.next; 555 Object k; 556 if (e.hash == hash && 557 ((k = e.key) == key || (key != null && key.equals(k)))) { 558 modCount++; 559 size--; 560 if (prev == e) 561 table[i] = next; 562 else 563 prev.next = next; 564 e.recordRemoval(this); 565 return e; 566 } 567 prev = e; 568 e = next; 569 } 570 571 return e; 572 } 573 574 /** 575 * Special version of remove for EntrySet. 576 */ 577 final Entry<K,V> removeMapping(Object o) { 578 if (!(o instanceof Map.Entry)) 579 return null; 580 581 Map.Entry<K,V> entry = (Map.Entry<K,V>) o; 582 Object key = entry.getKey(); 583 int hash = (key == null) ? 0 : hash(key.hashCode()); 584 int i = indexFor(hash, table.length); 585 Entry<K,V> prev = table[i]; 586 Entry<K,V> e = prev; 587 588 while (e != null) { 589 Entry<K,V> next = e.next; 590 if (e.hash == hash && e.equals(entry)) { 591 modCount++; 592 size--; 593 if (prev == e) 594 table[i] = next; 595 else 596 prev.next = next; 597 e.recordRemoval(this); 598 return e; 599 } 600 prev = e; 601 e = next; 602 } 603 604 return e; 605 } 606 607 /** 608 * Removes all of the mappings from this map. 609 * The map will be empty after this call returns. 610 */ 611 public void clear() { 612 modCount++; 613 Entry[] tab = table; 614 for (int i = 0; i < tab.length; i++) 615 tab[i] = null; 616 size = 0; 617 } 618 619 /** 620 * Returns <tt>true</tt> if this map maps one or more keys to the 621 * specified value. 622 * 623 * @param value value whose presence in this map is to be tested 624 * @return <tt>true</tt> if this map maps one or more keys to the 625 * specified value 626 */ 627 public boolean containsValue(Object value) { 628 if (value == null) 629 return containsNullValue(); 630 631 Entry[] tab = table; 632 for (int i = 0; i < tab.length ; i++) 633 for (Entry e = tab[i] ; e != null ; e = e.next) 634 if (value.equals(e.value)) 635 return true; 636 return false; 637 } 638 639 /** 640 * Special-case code for containsValue with null argument 641 */ 642 private boolean containsNullValue() { 643 Entry[] tab = table; 644 for (int i = 0; i < tab.length ; i++) 645 for (Entry e = tab[i] ; e != null ; e = e.next) 646 if (e.value == null) 647 return true; 648 return false; 649 } 650 651 /** 652 * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and 653 * values themselves are not cloned. 654 * 655 * @return a shallow copy of this map 656 */ 657 public Object clone() { 658 HashMap<K,V> result = null; 659 try { 660 result = (HashMap<K,V>)super.clone(); 661 } catch (CloneNotSupportedException e) { 662 // assert false; 663 } 664 result.table = new Entry[table.length]; 665 result.entrySet = null; 666 result.modCount = 0; 667 result.size = 0; 668 result.init(); 669 result.putAllForCreate(this); 670 671 return result; 672 } 673 674 static class Entry<K,V> implements Map.Entry<K,V> { 675 final K key; 676 V value; 677 Entry<K,V> next; 678 final int hash; 679 680 /** 681 * Creates new entry. 682 */ 683 Entry(int h, K k, V v, Entry<K,V> n) { 684 value = v; 685 next = n; 686 key = k; 687 hash = h; 688 } 689 690 public final K getKey() { 691 return key; 692 } 693 694 public final V getValue() { 695 return value; 696 } 697 698 public final V setValue(V newValue) { 699 V oldValue = value; 700 value = newValue; 701 return oldValue; 702 } 703 704 public final boolean equals(Object o) { 705 if (!(o instanceof Map.Entry)) 706 return false; 707 Map.Entry e = (Map.Entry)o; 708 Object k1 = getKey(); 709 Object k2 = e.getKey(); 710 if (k1 == k2 || (k1 != null && k1.equals(k2))) { 711 Object v1 = getValue(); 712 Object v2 = e.getValue(); 713 if (v1 == v2 || (v1 != null && v1.equals(v2))) 714 return true; 715 } 716 return false; 717 } 718 719 public final int hashCode() { 720 return (key==null ? 0 : key.hashCode()) ^ 721 (value==null ? 0 : value.hashCode()); 722 } 723 724 public final String toString() { 725 return getKey() + "=" + getValue(); 726 } 727 728 /** 729 * This method is invoked whenever the value in an entry is 730 * overwritten by an invocation of put(k,v) for a key k that‘s already 731 * in the HashMap. 732 */ 733 void recordAccess(HashMap<K,V> m) { 734 } 735 736 /** 737 * This method is invoked whenever the entry is 738 * removed from the table. 739 */ 740 void recordRemoval(HashMap<K,V> m) { 741 } 742 } 743 744 /** 745 * Adds a new entry with the specified key, value and hash code to 746 * the specified bucket. It is the responsibility of this 747 * method to resize the table if appropriate. 748 * 749 * Subclass overrides this to alter the behavior of put method. 750 */ 751 void addEntry(int hash, K key, V value, int bucketIndex) { 752 Entry<K,V> e = table[bucketIndex]; 753 table[bucketIndex] = new Entry<K,V>(hash, key, value, e); 754 if (size++ >= threshold) 755 resize(2 * table.length); 756 } 757 758 /** 759 * Like addEntry except that this version is used when creating entries 760 * as part of Map construction or "pseudo-construction" (cloning, 761 * deserialization). This version needn‘t worry about resizing the table. 762 * 763 * Subclass overrides this to alter the behavior of HashMap(Map), 764 * clone, and readObject. 765 */ 766 void createEntry(int hash, K key, V value, int bucketIndex) { 767 Entry<K,V> e = table[bucketIndex]; 768 table[bucketIndex] = new Entry<K,V>(hash, key, value, e); 769 size++; 770 } 771 772 private abstract class HashIterator<E> implements Iterator<E> { 773 Entry<K,V> next; // next entry to return 774 int expectedModCount; // For fast-fail 775 int index; // current slot 776 Entry<K,V> current; // current entry 777 778 HashIterator() { 779 expectedModCount = modCount; 780 if (size > 0) { // advance to first entry 781 Entry[] t = table; 782 while (index < t.length && (next = t[index++]) == null) 783 ; 784 } 785 } 786 787 public final boolean hasNext() { 788 return next != null; 789 } 790 791 final Entry<K,V> nextEntry() { 792 if (modCount != expectedModCount) 793 throw new ConcurrentModificationException(); 794 Entry<K,V> e = next; 795 if (e == null) 796 throw new NoSuchElementException(); 797 798 if ((next = e.next) == null) { 799 Entry[] t = table; 800 while (index < t.length && (next = t[index++]) == null) 801 ; 802 } 803 current = e; 804 return e; 805 } 806 807 public void remove() { 808 if (current == null) 809 throw new IllegalStateException(); 810 if (modCount != expectedModCount) 811 throw new ConcurrentModificationException(); 812 Object k = current.key; 813 current = null; 814 HashMap.this.removeEntryForKey(k); 815 expectedModCount = modCount; 816 } 817 818 } 819 820 private final class ValueIterator extends HashIterator<V> { 821 public V next() { 822 return nextEntry().value; 823 } 824 } 825 826 private final class KeyIterator extends HashIterator<K> { 827 public K next() { 828 return nextEntry().getKey(); 829 } 830 } 831 832 private final class EntryIterator extends HashIterator<Map.Entry<K,V>> { 833 public Map.Entry<K,V> next() { 834 return nextEntry(); 835 } 836 } 837 838 // Subclass overrides these to alter behavior of views‘ iterator() method 839 Iterator<K> newKeyIterator() { 840 return new KeyIterator(); 841 } 842 Iterator<V> newValueIterator() { 843 return new ValueIterator(); 844 } 845 Iterator<Map.Entry<K,V>> newEntryIterator() { 846 return new EntryIterator(); 847 } 848 849 850 // Views 851 852 private transient Set<Map.Entry<K,V>> entrySet = null; 853 854 /** 855 * Returns a {@link Set} view of the keys contained in this map. 856 * The set is backed by the map, so changes to the map are 857 * reflected in the set, and vice-versa. If the map is modified 858 * while an iteration over the set is in progress (except through 859 * the iterator‘s own <tt>remove</tt> operation), the results of 860 * the iteration are undefined. The set supports element removal, 861 * which removes the corresponding mapping from the map, via the 862 * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, 863 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> 864 * operations. It does not support the <tt>add</tt> or <tt>addAll</tt> 865 * operations. 866 */ 867 public Set<K> keySet() { 868 Set<K> ks = keySet; 869 return (ks != null ? ks : (keySet = new KeySet())); 870 } 871 872 private final class KeySet extends AbstractSet<K> { 873 public Iterator<K> iterator() { 874 return newKeyIterator(); 875 } 876 public int size() { 877 return size; 878 } 879 public boolean contains(Object o) { 880 return containsKey(o); 881 } 882 public boolean remove(Object o) { 883 return HashMap.this.removeEntryForKey(o) != null; 884 } 885 public void clear() { 886 HashMap.this.clear(); 887 } 888 } 889 890 /** 891 * Returns a {@link Collection} view of the values contained in this map. 892 * The collection is backed by the map, so changes to the map are 893 * reflected in the collection, and vice-versa. If the map is 894 * modified while an iteration over the collection is in progress 895 * (except through the iterator‘s own <tt>remove</tt> operation), 896 * the results of the iteration are undefined. The collection 897 * supports element removal, which removes the corresponding 898 * mapping from the map, via the <tt>Iterator.remove</tt>, 899 * <tt>Collection.remove</tt>, <tt>removeAll</tt>, 900 * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not 901 * support the <tt>add</tt> or <tt>addAll</tt> operations. 902 */ 903 public Collection<V> values() { 904 Collection<V> vs = values; 905 return (vs != null ? vs : (values = new Values())); 906 } 907 908 private final class Values extends AbstractCollection<V> { 909 public Iterator<V> iterator() { 910 return newValueIterator(); 911 } 912 public int size() { 913 return size; 914 } 915 public boolean contains(Object o) { 916 return containsValue(o); 917 } 918 public void clear() { 919 HashMap.this.clear(); 920 } 921 } 922 923 /** 924 * Returns a {@link Set} view of the mappings contained in this map. 925 * The set is backed by the map, so changes to the map are 926 * reflected in the set, and vice-versa. If the map is modified 927 * while an iteration over the set is in progress (except through 928 * the iterator‘s own <tt>remove</tt> operation, or through the 929 * <tt>setValue</tt> operation on a map entry returned by the 930 * iterator) the results of the iteration are undefined. The set 931 * supports element removal, which removes the corresponding 932 * mapping from the map, via the <tt>Iterator.remove</tt>, 933 * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and 934 * <tt>clear</tt> operations. It does not support the 935 * <tt>add</tt> or <tt>addAll</tt> operations. 936 * 937 * @return a set view of the mappings contained in this map 938 */ 939 public Set<Map.Entry<K,V>> entrySet() { 940 return entrySet0(); 941 } 942 943 private Set<Map.Entry<K,V>> entrySet0() { 944 Set<Map.Entry<K,V>> es = entrySet; 945 return es != null ? es : (entrySet = new EntrySet()); 946 } 947 948 private final class EntrySet extends AbstractSet<Map.Entry<K,V>> { 949 public Iterator<Map.Entry<K,V>> iterator() { 950 return newEntryIterator(); 951 } 952 public boolean contains(Object o) { 953 if (!(o instanceof Map.Entry)) 954 return false; 955 Map.Entry<K,V> e = (Map.Entry<K,V>) o; 956 Entry<K,V> candidate = getEntry(e.getKey()); 957 return candidate != null && candidate.equals(e); 958 } 959 public boolean remove(Object o) { 960 return removeMapping(o) != null; 961 } 962 public int size() { 963 return size; 964 } 965 public void clear() { 966 HashMap.this.clear(); 967 } 968 } 969 970 /** 971 * Save the state of the <tt>HashMap</tt> instance to a stream (i.e., 972 * serialize it). 973 * 974 * @serialData The <i>capacity</i> of the HashMap (the length of the 975 * bucket array) is emitted (int), followed by the 976 * <i>size</i> (an int, the number of key-value 977 * mappings), followed by the key (Object) and value (Object) 978 * for each key-value mapping. The key-value mappings are 979 * emitted in no particular order. 980 */ 981 private void writeObject(java.io.ObjectOutputStream s) 982 throws IOException 983 { 984 Iterator<Map.Entry<K,V>> i = 985 (size > 0) ? entrySet0().iterator() : null; 986 987 // Write out the threshold, loadfactor, and any hidden stuff 988 s.defaultWriteObject(); 989 990 // Write out number of buckets 991 s.writeInt(table.length); 992 993 // Write out size (number of Mappings) 994 s.writeInt(size); 995 996 // Write out keys and values (alternating) 997 if (i != null) { 998 while (i.hasNext()) { 999 Map.Entry<K,V> e = i.next(); 1000 s.writeObject(e.getKey()); 1001 s.writeObject(e.getValue()); 1002 } 1003 } 1004 } 1005 1006 private static final long serialVersionUID = 362498820763181265L; 1007 1008 /** 1009 * Reconstitute the <tt>HashMap</tt> instance from a stream (i.e., 1010 * deserialize it). 1011 */ 1012 private void readObject(java.io.ObjectInputStream s) 1013 throws IOException, ClassNotFoundException 1014 { 1015 // Read in the threshold, loadfactor, and any hidden stuff 1016 s.defaultReadObject(); 1017 1018 // Read in number of buckets and allocate the bucket array; 1019 int numBuckets = s.readInt(); 1020 table = new Entry[numBuckets]; 1021 1022 init(); // Give subclass a chance to do its thing. 1023 1024 // Read in size (number of Mappings) 1025 int size = s.readInt(); 1026 1027 // Read the keys and values, and put the mappings in the HashMap 1028 for (int i=0; i<size; i++) { 1029 K key = (K) s.readObject(); 1030 V value = (V) s.readObject(); 1031 putForCreate(key, value); 1032 } 1033 } 1034 1035 // These methods are used when serializing HashSets 1036 int capacity() { return table.length; } 1037 float loadFactor() { return loadFactor; } 1038 }
标签:resize size cts because opened alter ecif uil nsnull
原文地址:http://www.cnblogs.com/lssj9556/p/6874695.html