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