java.util.HashMap

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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="{@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 = e.value;
 385                 e.value = 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 = e.value;
 403                 e.value = 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 = 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 = 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 == 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 == 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 = 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 = value;
 711             value = 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 == 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 = (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的主要内容,如果未能解决你的问题,请参考以下文章

java.util.HashMap ----查看控制台,为什么打印顺序是这样的

java.util.HashMap和java.util.HashTable (JDK1.8)

java.util.HashMap 和 HashSet 的内部实现

Mabitis 多表查询resultType=“java.util.hashMap”

JAVA集合------Map (HashMap实现)

无法使用 HashMap 替换方法:调用需要 api 级别 24(当前最小值为 22):java.util.HashMap#replace