HashMap after JDK1.8

JDK1.7 previous HashMap

jdk1.7, when a conflict is generated in an address conflict list, the key element of the conflict by comparing equals, i.e. cover the same, is added to the different list, at this time, if the list is too long, the efficiency will greatly reduce the time and complexity of the lookup operation are added to O (n); however, if in jdk1.8 chain length is greater than 8 , the list will be transformed into red-black tree , but also reduced the time complexity of O (logn) performance has been greatly optimized.

When the number of red and black nodes 6 less will be converted back into the list. 

 Code analysis:

    /**
     The default initial capacity 16,0000 * right 4 0001 0001 0000 16, the initial capacity of the trunk 16 of the array, and the array
   * Must be a multiple of 2 (behind say why a multiple of 2)
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

    /**
     * Maximum capacity is 2 to the power 30
       */
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * Default load factor of 0.75
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * Threshold, if the length of the backbone chain of greater than 8 array, a linked list into red-black tree
     */
    static final int TREEIFY_THRESHOLD = 8;

    /**
     * After expansion hash table, if a red-black tree found a length of less than 6, the list will be re-reduced to
     */
    static final int UNTREEIFY_THRESHOLD = 6;

    /**
     * When hashmap capacity is greater than 64, can turn into a red-black tree list
     */
    static final int MIN_TREEIFY_CAPACITY = 64;
   /**
     * = Threshold array trunk capacity load factor * * DEFAULT_LOAD_FACTOR DEFAULT_INITIAL_CAPACITY 
* /
    int threshold;

 HashMap constructor:

// initialCapacity initial capacity, the load factor loadFactor 
public the HashMap ( int initialCapacity, a float loadFactor) {
    // initial capacity is less than 0, the illegal data thrown exception
IF (initialCapacity <0 ) the throw new new an IllegalArgumentException ( "Illegal Initial Capacity:" + initialCapacity);
    // maximum initial capacity MAXIMUM_CAPACITY
IF (initialCapacity> MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY;
    //校验 loadFactor 合法性
if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); the this .loadFactor = loadFactor;
    // The initial capacity of 2 to turn power
the this .threshold = tableSizeFor (initialCapacity); }
 // tableSizeFor role is, if the incoming A, when A is greater than 0 and less than the maximum capacity defined,
   //   if A is a power of 2 A is returned, otherwise larger than A into a minimum distance of A and 2 power.  
    // e.g. incoming return 8 7, 8 passed 8 returns, returns passed 9 16 
 static  Final  int tableSizeFor ( int CAP) {
         int n-CAP = -. 1 ;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
  // default constructor, load factor is 0.75, an initial capacity of DEFAULT_INITIAL_CAPACITY = 16, the initial capacity will be put at the first initialization

public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

put method: 

 static final int hash(Object key) {

int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

 

  public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
  

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { The Node <K, V> [] Tab; the Node <K, V> P; int n-, I;
// if the trunk table is empty, a length of 0, resize method calls, length adjustment table (
IF ((Tab Table =) == null || (= n-tab.length) == 0 )

  / * This call resize, in fact, the first time put, the array is initialized. * /

            n = (tab = resize()).length;

      // deposit key does not exist, stored in the new key
         IF ((P = Tab [I = (n--. 1) & the hash]) == null )
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
        //key存在
if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k)))) E = p;
        // p is determined whether a red-black tree node
the else IF (p the instanceof the TreeNode) E = ((the TreeNode <K, V>) P) .putTreeVal ( the this , Tab, the hash, Key, value); the else {// the new node is neither the same as P, p is not treenode Examples for ( int BinCount 0 =;; ++ BinCount) { IF ((E = p.next) == null ) { p.next = the newNode (the hash, Key, value, null );
                // If the chain length greater than or equal. 8
IF (BinCount> = TREEIFY_THRESHOLD -. 1) // -1 for 1st
                  
// list into the red-black tree treeifyBin (tab , hash); BREAK ; } if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } IF (E! = null ) { // existing Key Mapping for

        // if the added elements generated hash conflicts, then the method call // put, he will be a value on his return element in the list

V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++ ModCount; 
    //
if the number of elements is greater than the threshold value, for expansion
if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

Into a red-black tree:

  Final  void treeifyBin (the Node <K, V> [] Tab, int the hash) {
         int n-, index; the Node <K, V> E;
       // array length is less than 64, again not converted to red-black tree expansion 
        IF (Tab == null || (= n-tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            The TreeNode <K, V> HD = null , TL = null ;
             do { // into red-black tree 
                the TreeNode <K, V> P = replacementTreeNode (E, null );
                 IF (TL == null )
                    hd = p;
                else {
                    p.prev = tl;
                    tl.next = p;
                }
                tl = p;
            } while ((e = e.next) != null);
            if ((tab[index] = hd) != null)
                hd.treeify(tab);
        }
    }    

 

Detailed resize source, expansion mechanism, how single-element array to the new hash, how the list of elements hashing to the new array, how red-black tree elements in the hash to the new array?

 final Node<K,V>[] resize() {
        The Node <K, V> [] = oldTab Table;
         int OLDCAP = (oldTab == null ) 0? : OldTab.length;
         int oldThr = threshold;
         int newCap, newThr = 0 ;
         IF (OLDCAP> 0) {   // expansion execution branches 
            iF (OLDCAP> = MAXIMUM_CAPACITY) {    // the maximum is exceeded, the threshold value is set to a maximum value when the capacity int 
                threshold = Integer.MAX_VALUE;
                 return oldTab;
            }
            the else  IF ((newCap = OLDCAP <<. 1) <MAXIMUM_CAPACITY && OLDCAP > = DEFAULT_INITIAL_CAPACITY) // expansion capacity of two times the critical value of 2 times 
                newThr = oldThr <<. 1 ;
        }
        else if (oldThr > 0) 
            newCap = oldThr;
        else {               
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        if (newThr == 0) {  
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        threshold = newThr;     // new threshold value assigned to the assigned threshold 
        the Node <K, V> [] = newtab (the Node <K, V> []) new new the Node [newCap];
        table = newtab;    // new array table assigned to
 
        // After the expansion, the newly calculated position of the element 
        IF (oldTab =! Null ) {    // original array 
            for ( int J = 0; J <OLDCAP; J ++) {    // iterate through the original capacity of the original array 
                Node <K , V> E;
                 iF (! (E = oldTab [j]) = null ) {    // determines whether the node is empty, the node position j
                         oldTab [j] = null ;
                     iF (e.next == null )           // determine whether the list Node 
                        newtab [& e.hash (newCap -. 1)] = E; // no list, determine the elemental storage position,
                     the else  iF (e instanceof TreeNode)
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    else { // preserve order
                        Node<K,V> loHead = null, loTail = null;
                        Node<K,V> hiHead = null, hiTail = null;
                        Node<K,V> next;
                do { next = e.next; if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e is the; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null ; // tail node next to an empty newtab [J] = loHead; } if (hiTail != null) { hiTail.next = null ; // tail node next to an empty newtab [J + OLDCAP] = hiHead; } } } } } Return newtab; }

 

//红黑树
final
void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) { TreeNode<K,V> b = this; // Relink into lo and hi lists, preserving order TreeNode<K,V> loHead = null, loTail = null; TreeNode<K,V> hiHead = null, hiTail = null; int lc = 0, hc = 0; for (TreeNode<K,V> e = b, next; e != null; e = next) { next = (TreeNode<K,V>)e.next; e.next = null; if ((e.hash & bit) == 0) { if ((e.prev = loTail) == null) loHead = e; else loTail.next = e; loTail = e is the; ++ lc; } else { if ((e.prev = hiTail) == null) hiHead = e; else hiTail.next = e; hiTail = e; ++hc; } } IF (loHead! = null ) {
// list of less than 6 into
IF (LC <= UNTREEIFY_THRESHOLD) tab[index] = loHead.untreeify(map); else { tab[index] = loHead; if (hiHead != null) // (else is already treeified) loHead.treeify(tab); } } if (hiHead != null) { if (hc <= UNTREEIFY_THRESHOLD) tab[index + bit] = hiHead.untreeify(map); else { tab[index + bit] = hiHead; if (loHead != null) hiHead.treeify(tab); } } }

 

Guess you like

Origin www.cnblogs.com/fanBlog/p/11692419.html