HashMap之put方法源码解析

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict)
	{
		Node<K, V>[] tab;// tab就是数组(散列桶)
		Node<K, V> p;// 而p是每个桶
		int n, i;
		// tab刚开始是null或者大小为0,则进行扩容操作resize(),返回值为Node<K,V>[],直接赋值给tab,初始化tab。
		if ((tab = table) == null || (n = tab.length) == 0)
			n = (tab = resize()).length;
		// 初始化之后通过位与运算(求余)找到put的index,如果该位置没有元素也就是tab[index]==null,那么tab[i]
		// =newNode(hash, key, value, null);即put成功
		if ((p = tab[i = (n - 1) & hash]) == null)
			tab[i] = newNode(hash, key, value, null);
		// 当然我们知道hash冲突是有的,所以当tab[index]!=null时,也就发生了hash冲突
		else
		{
			Node<K, V> e;
			K k;
			// 如果是key已存在
			if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
				e = p;
			// 如果不是重复的,那么就看p是否是树节点,因为jdk1.8中采用的是红黑树,所以要考虑树节点,如果是树节点就进行树节点的put
			else if (p instanceof TreeNode)
				e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
			else// 如果不是重复的,也没有树节点,那就是hash冲突并且使用链表处理了;
			{
				// 遍历链表结点
				for (int binCount = 0;; ++binCount)
				{// 遍历到了末尾也没发现重复的key,那么就是就执行一个插入操作
					if ((e = p.next) == null)
					{
						p.next = newNode(hash, key, value, null);
						// 当如果是链表存储时,如果插入元素之后超过了TREEIFY_THRESHOLD,还要进行树化操作。从链表变为红黑树
						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;
				}
			}
			if (e != null)// map中已经存在key了,则修改旧值,并返回旧值
			{ // existing mapping for key
				V oldValue = e.value;
				if (!onlyIfAbsent || oldValue == null)
					e.value = value;
				afterNodeAccess(e);
				return oldValue;
			}
		}
		++modCount;
		// 最后进行一个判断,看size是否到达了扩容标准,如果达到了进行扩容resize();
		if (++size > threshold)
			resize();
		afterNodeInsertion(evict);
		return null;
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值