JDK1.8_HashMap source __ constructor

HashMap underlying Node implementation is a type of array, i.e. using PUT (key, value) method to put the key and value when there is a corresponding table according to the array index value hashcode, source code as follows:

    /**
     * The table, initialized on first use, and resized as
     * necessary. When allocated, length is always a power of two.
     * (We also tolerate length zero in some operations to allow
     * bootstrapping mechanics that are currently not needed.)
     */
    transient Node<K,V>[] table;

Node is a generic class implements Map.Entry, source code is as follows:

    /**
     * Basic hash bin node, used for most entries.  (See below for
     * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
     */
    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

2 HashMap constructor

HashMap There are four constructors:

public HashMap()
public HashMap(int initialCapacity)
public HashMap(int initialCapacity, float loadFactor)
public HashMap(Map<? extends K, ? extends V> m)

2.1 No argument constructor: public HashMap ()

    /**
     * Constructs an empty <tt>HashMap</tt> with the default initial capacity
     * (16) and the default load factor (0.75).
     */
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

Official in HashMap () constructor's comments said: "Using the default initial capacity (16) and the default load factor (0.75) to construct an empty HashMap", but only the source code to initialize the default initialization loadFactor without capacity, then where initial capacity of it?

Since capacity is not initialized in the constructor, then add in the use of methods to put hashMap element in how the situation will happen then?

Here let us put approach check it out now!

public V PUT (Key K, V value) { 
      // called here the following method PutVal
return PutVal (the hash (Key), Key, value, to false , to true ); }

Final V PutVal ( int the hash, Key K, value V , Boolean onlyIfAbsent, Boolean The evict) { the Node <K, V> [] Tab; the Node <K, V> P; int n-, I; // if the table is empty or a length of 0, first for expansion IF ((Tab = Table) == null || (= n-tab.length) == 0 ) n- = (Tab =. a resize ()) length;       // remaining codes omitted. . . . . . }

In order not to interfere with this first code being less than ignored, we can see from the source code is highlighted in yellow, put in the time when the table is null or length of 0 will be called once resize method expansion, what happened then resize method?

    Final the Node <K, V> [] a resize () {
         // 1. Table here because it is still not initialized to null 
        the Node <K, V> [] = oldTab Table;
         // 2. At this time, a value of 0 oldCap 
        int OLDCAP = (oldTab == null ?) 0 : oldTab.length;
         // 3. obtain old expansion threshold, the threshold has not been assigned at this time, so it is the default value 0 
        int oldThr = threshold;
         int newCap, newThr = 0 ;
         // if there is an old element in the table, clearly does not meet the conditions where 
        IF (OLDCAP> 0 ) {
            // ignore independent code 
        } the else  IF (oldThr> 0) // initial capacity was placed in threshold
            newCap = oldThr;
        else {               // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        if (newThr == 0) {
       //5. threshold变成了table数组长度与加载因子的积
            float ft = (float) newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float) MAXIMUM_CAPACITY ?
                    (int) ft : Integer.MAX_VALUE);
        }
        threshold = newThr;

        @SuppressWarnings({"rawtypes", "unchecked"})

        Node<K, V>[] newTab = (Node<K, V>[]) new Node[newCap];
        table = newTab;

          //忽略无关代码

        return newTab;
    }

Note: Here there is a variable threshold, threshold is used to determine whether the threshold table capacity is needed, and when the number of elements in the table is greater than the threshold table will be expansion.

You can clearly see from the yellow highlighted code, resize method DEFAULT_INITIAL_CAPACITY size of the array to create a new array replaces the old array is.

And the expansion threshold to DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY i.e. 16 * 12 = 0.75

 

2.2 specified initial capacity constructor: public HashMap (int initialCapacity)

    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

Source can be seen in the constructor calls a specified initial capacity and load factor of the constructor and load factor as the default value (0.75).

2.3 specified initial capacity and load factor constructor: public HashMap (int initialCapacity, float loadFactor)

    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }

First, the source code for initialCapacity and loadFactor verified, after setting the expansion threshold value threshold, and (keep in mind that this variable will be used when it will be initialized table array)

tableSizeFor method is how to set the threshold value of it? This method is explained in detail in another essay in: HashMap source __tableSizeFor analytical method

Now we need to know this method returns the number of the smallest integer power of 2 less than the parameter is not a cap, such as cap 10, return 16, cap 17, 32 is returned.

Array initialization table

By analyzing the source code for the above constructor found for the table array storage elements are not initialized in the constructor, then the table when the array is initialized it? The answer call put method when the time! Mentioned end of the preceding constructor with no arguments too, PUT method calls putVal method, the method table putVal array of expansion, and therefore directly below the point of view resize method:

    Final the Node <K, V> [] a resize () {
         // Table. 1 here because it is still not initialized to null. 
        the Node <K, V> [] = oldTab Table;
         . // 2 0 value at this time oldCap 
        int OLDCAP = (oldTab == null ?) 0 : oldTab.length;
         .. 3 // Get the old expansion threshold value, since the value is set too threshol in the constructor, so here is not a small value threshol specified minimum capacity 2 the integer power 
        int oldThr = threshold;
         int newCap, newThr = 0 ;
         // if there are elements of the old table, it is clear here is not eligible 
        IF (OLDCAP> 0 ) { 
           // ignore independent code 

      . // 4 focus here Since oldThr been assigned, and it will perform the method body newCap = oldThr, so that the capacity of a table to the array becomes the value of the aforementioned threshol } the else if (oldThr > 0) // initial capacity was placed in threshold newCap = oldThr; else { // zero initial threshold signifies using defaults newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } if (newThr == 0) {
       //5. threshold变成了table数组长度与加载因子的积
float ft = (float) newCap * loadFactor; newThr = (newCap < MAXIMUM_CAPACITY && ft < (float) MAXIMUM_CAPACITY ? (int) ft : Integer.MAX_VALUE); } threshold = newThr; @SuppressWarnings({"rawtypes", "unchecked"}) Node<K, V>[] newTab = (Node<K, V>[]) new Node[newCap]; table = newTab; //忽略无关代码 return newTab; }

 

Guess you like

Origin www.cnblogs.com/jiamengwei/p/11228458.html