HashMap 源码分析

导读:本篇文章讲解 HashMap 源码分析,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

HashMap 源码分析 步步分析

1,首先看到put方法

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

	/**
	* 其当前方法是为了减少hash碰撞,降低hash冲突的几率
	*/
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

2,往里追,putVal方法

 /**
 * putVal 则是当前hashMap核心方法之一
 */
 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> 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<K,V> 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<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
            /**
            * 如果以上两个条件都不满足,则说明当前是一个链表形式的
            * 所以我们可以看到,在其for循环,主要做的事情,循环对比
            * 链表上的每一个节点,如果有一个节点相同,则break;
            */
            	// 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;
                    }
         /**
         * 如果上面p.next是有值的,则不会进入上面那个判断,则会进入当前
         * 这个判断,其实这个判断跟刚刚开始进putVal方法那个判断大同小异
         * 如果在当前循环比较过程中,发现有相同的,就break
         * 则后面 就会进到if (e != null)这个判断里面去
         * 如果没有相同,则把当前这个e赋值这个p,
         * 在下次循环的开始if ((e = p.next) == null),由此可见
         * p.next 又赋值了e 一节一节往后走,真是一个巧妙的设计
         */
                    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;// 添加成功
    }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/112577.html

(0)
Java光头强的头像Java光头强

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!