Algorithms and Data Structures (eight) HashMap source

A storage structure 

static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
transient Node<K,V>[] table;

An internal storage unit shown above, a whole array of barrel is added to the list.

Two put operations

put (key, value) is called internally PutVal () The following is the source jdk1.8 interpolation is used in the tail  

Final V PutVal (int the hash, K Key, V value, Boolean onlyIfAbsent, 
                   Boolean The evict) { 
        the Node <K, V> [] Tab; the Node <K, V> P; int n-, I; 
        IF ((Tab = Table) null || == (n-tab.length =) == 0) 
            n-= (Tab = a resize ()) length;. // If this is the first element of the array is initialized lazy loading 
        if ((p = tab [i = (n--. 1) & the hash]) == null) 
            Tab [I] = the newNode (the hash, Key, value, null); // if the current position has not initialize the current position of the element position determination method herein is & calculating 
        else {// find the node (key for Key) 
            the node <K, V> E; K K; 
            IF (p.hash the hash == && 
                ((K = p.key) == || Key (Key =! && key.equals null (K)))) 
                E = P;       
            the else IF (the instanceof the TreeNode P)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }  
// The following code if to linkedhashmap service IF (E = null!) {// existing Key Mapping for V = oldValue e.Value; (! OnlyIfAbsent oldValue == null ||) IF e.Value = value; afterNodeAccess ( E); return oldValue; } } ++ ModCount;
// if the capacity of the ultra-expansion on the IF (size ++> threshold) a resize (); afterNodeInsertion (the evict); return null; }

  In addition to the code portion of the two lead-out portions of the red-black tree: 1 -1 Why length hash & taken to find ways how to array location 2. Expansion

 

Three initialization and expansion 

The method of Capacity:

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;
    }

  For the constructor integer passed, the following steps. The conclusion is that the number obtained is greater than the minimum power value is equal to 2 is passed. 64 is passed is 64, 127 is passed 128.

This algorithm not want to think of it, but look at the code is easy to understand. 65 For this, 1 is subtracted, is 1,000,000 1,100,000 The first operation is a second: 1111000, 1111111 result becomes (all 1) must be the last with a whole power of two.

This also solves the hash function Why hash & n-1, because of the efficiency of more than & division and modulo operation, and because it is an integer power of 2, and bitwise modulo operation with the same effect, but much faster.

 

Moreover node node hash value, is thus obtained, that is, the original 16-bit and high hashcode Key or will hashcode. In order to increase the sense of 16 high participation, reduce hash conflicts, if the key hashcode is 0A01 0B01 0C01 directly if bitwise operations, they are mapped to the same location, but after such an action would reduce cases hash collision.

Final int the hash static (Object Key) { 
int H;
return (Key == null) 0:? (H = key.hashCode ()) ^ (H >>> 16);
}

while the expansion is mainly this method is to resize the code segment, a new array is twice the old array, as old data is migrated to the new array
IF (oldTab = null!) { 
            for (int J = 0; J <OLDCAP; J ++) { 
                the Node <K, V> E;    
                IF (! (E = oldTab [J]) = null) {     
                    oldTab [J ] = null; 
                    IF (e.next == null) // first case, the node element 
                        newTab [e.hash & (newCap - 1 )] = e; // current node position in the new node 
                    else if (e instanceof TreeNode) // second case, the node is a red-black tree 
                        ((the TreeNode <K, V>) E) .split (the this, newtab, J, OLDCAP); 
                    the else {// // Order of the preserve three cases are linked list node 
                        the node <K, V> = null loHead, loTail = null; 
                        the node <K, V> = null hiHead, hiTail = null;
                        The Node <K, V> Next; 
                        do {// capacity is divided into two categories, such as the old hash 17 1 to 16 they are at an index position 1, however & 16, is either 0 or 1. This is the standard for the classification of 0 on the location of the new array 1, 1 is placed in position 17 of the 
                            Next = e.next; 
                            IF ((e.hash & OLDCAP) == 0) { 
                                IF (= loTail null =) 
                                    loHead = E; 
                                the else 
                                    loTail.next = E; 
                                loTail = E; 
                            } 
                            the else { 
                                IF (hiTail == null) 
                                    hiHead = E; 
                                the else 
                                    hiTail.next = E;
                                hiTail = e;
                            }
                        } while ((e = next) != null);
                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead;
                        }
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }

  Four summary

Algorithm 1 .hash value, hash value and the high or will bond 16, to retain high information

        --- & map index value (volume -1) to give an actual

2. ensure that capacity is 2 powers to take Bitwise or  

3. .hashMap of structure 

                 1.8 change made, plus an array of red-black tree list tree will become greater than 8,

                  Consideration change the tree is relatively high, so it added a condition that the array size is greater than 64, or else take the method of expansion, the list is too long to solve the problem.

4.hashmap key can be inserted null

                A separate method, is always inserted in the first list, i.e. the position of array subscript 0

The traversal methods 

           map.entrySet () which is to get all the key-value pairs

            keyset () This is to get all the key

6. concurrency problem

             put () lost updates

             resize () may also lose Update

 

Guess you like

Origin www.cnblogs.com/caijiwdq/p/11072465.html