HashMap 源码分析

HashMap 源码分析,第1张

HashMap 源码分析 HashMap 源码分析 步步分析

1,首先看到put方法

    public V put(K key, V value) {
    	// 在其中调用了hash方法
        return putVal(hash(key), key, value, false, true);
    }

	
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

2,往里追,putVal方法

 
 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node[] tab; Node p; int n, i;
        // 进入第一层判断,判断是否表是否为null,
        // 则会去调用resize()方法,完成对table的初始化
        // 其在resize里面做的一个事情,加载因子*当前数组的容量,
        // 默认16,所以就是 0.75 * 16 = 12,得出一个临界值
        // 则临界值,是当我们容量到达临界值时,完成的一个扩容的过程
        if ((tab = table) == null || (n = tab.length) == 0)
        // 初始化,感兴趣的小伙伴,可以往resize()里面追
            n = (tab = resize()).length;
        // 通过hash过后得到一个索引位置,判断当前位置是否有值,
        // 如果没有值,则创建一个新的节点
        if ((p = tab[i = (n - 1) & hash]) == null) // 确定当前位置没有值
        // 首次加入话,必定会加进去的
            tab[i] = newNode(hash, key, value, null); 
        else {// 当前位置有值
        	// 如果当前值,则会进行多次判断
            Node e; K k;
       // 首先第一次判断,判断当前索引的第一个位置的hash值是否跟
       // 我正在添加进去的hash值是否相同,如果相同则 p 赋值给 e 
       // 之后就会完成值的替换
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode) // 判断当前是否为树型
               // 如果为树形,则会已树形的方式添加
                e = ((TreeNode)p).putTreeval(this, tab, hash, key, value);
            else {
            
            	// for 死循环
                for (int binCount = 0; ; ++binCount) {
                // p.next赋值给e 判断是否为null, 也就是说判断下个节点
                // 是否有值
                    if ((e = p.next) == null) {
                    // 如果确实等于null 则在当前p的下个节点创建
                    // 一个新的节点
                        p.next = newNode(hash, key, value, null);
                       
                       // 判断链表长度>=8 table长度>=64 转换为红黑树
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        	//会去调用treeifyBin方法,则不会马上进行
                        	//树化,在treeifyBin中判断了table.length
                        	//如果满足两个条件才会进行红黑树化
                            treeifyBin(tab, hash);
                        break;
                    }
         
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
		// 其当前判断,也就是我们上面所说的,如果满足当前条件
		// 则意味着添加失败,因为它们在当前找到了那个值,并赋值给了e		
            if (e != null) { // existing mapping for key
               // 原来的旧值提取出来
                V oldValue = e.value;
                //onlyIfAbsent 传进来就是false,取反则为true
                if (!onlyIfAbsent || oldValue == null)
                  // e.value = value; 这意味着当前当前新的value给
                  // 到了e.value ,从而发生了替换
                  // 这就是为什么HaspMap value 可以重复,如果key重复
                  // 则key的value会被替换
                    e.value = value;
                afterNodeAccess(e); // 空实现方法,交给子类去实现的
               //如果返回有值,则是添加失败,返回null,则添加成功
                return oldValue; // 添加失败
            }
        }
        ++modCount;// 修改次数加加
        // 当前table容量值 是否大于 临界值
        if (++size > threshold)
            resize(); // 如果满足 开始扩容
        afterNodeInsertion(evict); // 空实现方法,交给子类去实现的
        return null;// 添加成功
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5721690.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存