hashMap 1.8 源码及原理浅析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wzl1369248650/article/details/82387131

这里主要讲源码流程,原理只做简单介绍

  • hashMap原理浅析

hashMap 的结构是由数组+链表构成,数组为Node[] table,链表节点为Node。

  • map.put(key,value),根据(table.length - 1) & hash(key)进行散列到table的某一个位置。当key值相同时(hash碰撞),则遍历链表(即Node的每一个next),如果有相同key的则覆盖,否则将添加进链表

  • 当size > threshold(元素数量大于容纳数量)时进行resize()扩容操作,以原有table*2进行扩容。1.7实现将现有数据进行重新散列;1.8判断e.hash & oldCap == 0(即数组第一位)时在原区间,否则在新增区间同一位置。

  • hashMap基本属性


//默认初始容量-必须是2的幂
DEFAULT_INITIAL_CAPACITY = 1 << 4;

//最大容量
MAXIMUM_CAPACITY = 1 << 30;

//默认负载因子
DEFAULT_LOAD_FACTOR = 0.75f;

//一个桶的树化阈值,当桶中元素个数超过这个值时,使用红黑树替换现有节点
TREEIFY_THRESHOLD = 8

//一个树的链表还原阈值,当扩容时,桶中元素个数小于这个值,就会把红黑树还原成链表
UNTREEIFY_THRESHOLD = 6

/**哈希表的最小树形化容量,
当哈希表中的容量大于这个值时,表中的桶才能进行树形化。
否则桶内元素太多时会扩容,而不是树形化。
为了避免进行扩容、树形化选择的冲突,这个值不能小于 4*TREEIFY_THRESHOLD
*/
MIN_TREEIFY_CAPACITY = 64

//具体的元素存储
Node[] table

//元素的数量
int size

//修改次数
int modCount

//在下一次resize ()调用之前的容量大小,也就是capacity ,默认为capacity*loadFactor
int threshold

//加载因子
float loadFactor

  • 源码

hashMap核心Node节点

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

插入一个元素

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

1 判断table是否为空,为空新建一个
2 判断key的hash散列是否存在,不存在直接新建一个链表节点
3 判断元素是否和链表第一个元素相同,相同则覆盖
4 循环链表节点
5 判断是不是尾节点,是增新增节点
6 判断是否超过阀值,超过则用红黑树替换链表
7 判断元素是否和链表元素相同,相同则覆盖。循环节点结束
8 对新增或覆盖元素进行value赋值
9 判断是否超过容量,超过则进行扩容

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        //判断table是否为空
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
         //判断key的hash散列是否存在
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            //判断元素是否和链表第一个元素相同,相同则覆盖
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                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) 
	                        //**超过阀值,用红黑树替换链表。红黑树代码此处不讨论**
                            treeifyBin(tab, hash);
                        break;
                    }
                    //判断元素是否和链表元素相同,相同则覆盖
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            //赋值操作
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        //超过容量,进行扩容
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

猜你喜欢

转载自blog.csdn.net/wzl1369248650/article/details/82387131