HashMap源码分析 - HashMap的数据结构

HashMap源码分析

HashMap的数据结构

1.数组:
2.链表:双向链表
3.红黑树:二叉查找数

源码中验证:

	 /**
     * Holds cached entrySet(). Note that AbstractMap fields are used
     * for keySet() and values().
     */
	 transient Node<K,V>[] table;
	
	/**
     * 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;
		}
	 /**
     * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
     * extends Node) so can be used as extension of either regular or
     * linked node.
     */
    static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
    
    
        TreeNode<K,V> parent;  // red-black tree links
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;
        }

put操作

1.数组初始化:
通过resize()方法来进行初始化操作:
数组默认大小;
		static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
		newCap = DEFAULT_INITIAL_CAPACITY;
		Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
		table = newTab;
2.存储Node节点:
if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
3.链表(进行树化)存储:
 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;
                }
TREEIFY_THRESHOLD :链表转树的判断值;
UNTREEIFY_THRESHOLD:树转链表的判断值;

4.检查数组是否进行扩容:

 if (++size > threshold)
            resize();

确定数组下标

如何确定数组下标在和位置:

if ((p = tab[i = (n - 1) & hash]) == null)
从这里可以知道数组下标是如何进行确定的;通过hash值与n-1(默认是15)进行与操作;通过二进制进行操作;

数组扩容

数组的扩容操作是在resize()操作中进行扩容;

 if (++size > threshold)
            resize();
            
 threshold = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
 //计算触发扩容值:这里针对默认情况进行计算 16*0.75f;
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
扩容是进行double操作;

数组扩容之后,之前的节点需要进行重新排列:

1.当前节点只有一个节点
if (e.next == null)
  	newTab[e.hash & (newCap - 1)] = e;
2.树节点,进行切割,重新插入到数组中:
 else if (e instanceof TreeNode)
      ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
3.编列链表:
 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;
                            }
                            else {
    
    
                                if (hiTail == null)
                                    hiHead = e;
                                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;
                        }

避免hash冲突

hash记性修改:对key,hashCode的高16位与低16位进行异或运算;
重复几率太大了 --->尽可能避免hash冲突,result结果要尽可能不一样 ---->参与运算的位数只有最后几位?不合理,---->hashCode 32 32利用的淋漓尽致;

猜你喜欢

转载自blog.csdn.net/Bruce_Zhang0828/article/details/102767603