HashMap的部分源码解读

HashMap的部分源码解读

1、put(key,value)


	public V put(K key, V value) {
		//此处参数内hash(key),实际上是获得key的hashCode值
		return putVal(hash(key), key, value, false, true); 
	}

	// onlyIfAbsent值为false的时候表示直接覆盖已存在的key的value值,为true时oldValue为null则才会覆盖
	final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
        // 声明一个tab数组
		Node<K,V>[] tab; 
		// 声明一个节点Node键值对
		Node<K,V> p; 
		// n表示tab的size; 表示即将把值put到某个Node(key-value)的index
		int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
			// 如果tab为空或者长度为0时,就初始化tab(初始长度为16),并将长度值赋给n
            n = (tab = resize()).length;
		// 当(n - 1) & hash 位与运算的结果为key对应的index,当为空的时候
        if ((p = tab[i = (n - 1) & hash]) == null)
			// 则调用newNode方法新建一个Node对象赋值给tab[i]
            tab[i] = newNode(hash, key, value, null);
        else {
			//  进入此else的代码块,则表示tab对应index必定已存在Node对象
            Node<K,V> e; 
			// 泛型 对象k  代表key
			K k;
			// 当对应index上的Node的hash值与传入进来的key的hash值相等并且Node的key和传入的key也相等时则覆盖value值
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
			// 当上面不成立的时候,则说明此Node可能是红黑树或者链表. 当 是红黑树的时候
            else if (p instanceof TreeNode)
				// 当为红黑树时,调用putTreeVal方法,此方法内部会遍历红黑树,如果已存在则返回被覆盖的Node,否则返回null
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
				// 当为链表时,循环遍历链表
                for (int binCount = 0; ; ++binCount) {
					// 当p.next为空时
                    if ((e = p.next) == null) {
						// 则newNode方法新建一个Node对象赋值给p.next
                        p.next = newNode(hash, key, value, null);
						// 当链表达到一定长度(默认8)后,调用treeifyBin方法转换成红黑树的结构
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
							// 当遍历到p.next为空时 则表示找到了可以放置put进来的key-value的地方,所以要结束链表遍历
                            treeifyBin(tab, hash);
                        break;
                    }
					// 当p.next不为空时,并且hash值和传入的hash值相等,key值也相等时,则覆盖值,结束循环
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
						// 则表示覆盖值,结束循环
                        break;
					//因为链表的遍历是 p.next.next.next...这种形式,所以最后需要将e赋给p
                    p = e;
                }
            }
			//此处是真正执行覆盖操作的地方
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
				//onlyIfAbsent传入为false,所以会直接覆盖e原来的value值
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
				//afterNodeAccess此方法下面没有代码所以无实际意义
                afterNodeAccess(e);
				// 这个地方可以看出 当我们put重复的key-value时  会返回被覆盖的oldValue,虽然我们一般不关心put时候的返回值
                return oldValue;
            }
        }
		//modCount是统计map被修改次数的
        ++modCount;
		//当tab的size大于阈值的时候则需要调用resize方法进行扩容
        if (++size > threshold)
            resize();
		//afterNodeInsertion此方法下面没有代码所以无实际意义
        afterNodeInsertion(evict);
		//当put的时候不存在覆盖值的时候则返回null
        return null;
    }


2、get(key)

	public V get(Object key) {
    	Node<K, V> e;
    	return (e = getNode(hash(key), key)) == null ? null : e.value;
	}

	final Node<K,V> getNode(int hash, Object key) {
		Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
		// 当tab不为空并且长度不为0的情况下,并且通过hash值和长度-1的位运算计算出的table[index]不为空
		if ((tab = table) != null && (n = tab.length) > 0 &&
			(first = tab[(n - 1) & hash]) != null) {
			// check匹配上的index处的节点,比较key值是否相等
			if (first.hash == hash && // always check first node
				((k = first.key) == key || (key != null && key.equals(k))))
				//相等则直接返回节点
				return first;
			//当第一个节点匹配不上则就说明是链表或者红黑树
			if ((e = first.next) != null) {
				//当节点元素为红黑树的时候
				if (first instanceof TreeNode)
					//红黑树TreeNode内部匹配结果
					return ((TreeNode<K,V>)first).getTreeNode(hash, key);
				do {
					if (e.hash == hash &&
						((k = e.key) == key || (key != null && key.equals(k))))
						//当为链表的时候则使用next指针遍历整个链表直到匹配上或者遍历完
						return e;
				} while ((e = e.next) != null);//当下一个节点不为空时,继续比较key值是否匹配(执行do{}代码块)
			}
		}
		return null;
	}

3、链表红黑树互转

hashmap链表转化成红黑树的过程以及红黑树转化成链表的过程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值