Java8源码分析HashMap的get和put

put方法

/**
     * 将指定值与该映射中的指定键相关联。
     * 如果map中key的值已经存在,则新的值会取代旧的值
     */
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

    /**
     * 实现Map的put方法以及相关方法
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent if true, 不存在key对应的value
     * @param evict if false, 表处于创建模式.
     * @return previous value, or null if none
     */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
/**
	注释:先进性赋值 tab = table  ; n= tab.length;
	如果表为table=null 或者table的长度为0,则调用 resize());方法将tab初始化,n为新创建table的长度16
*/
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;

/**
	i = (n - 1) & hash是根据key值经过hash算法后获取所在数组的索引。
	tab[i = (n - 1) & hash]);获取数组索引出的链表( Node<K,V>);并且把p = 这个链表
	if 链表为null,就再索引处新建一个链表结构
*/
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
//下面是 索引处的存在链表
        else {
            Node<K,V> e; K k;
         /**
			if else if else 是为了给e赋值。由于当链表长度超过8的时候,就会变为红黑树结构。	
		*/
//如果存在和key相等的node,则将node取出,以便下面替换已经存在的值
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
                //如果索引为红黑树结构,则将值放入平衡树中,并返回这个TreeNode 赋值给e,以便后面操作
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else { //非红黑树结构
            //既然没有key的node,找到最后一个node,并且把这个新的key-value生成一个node,
            //并把这个新node放到这个node的next下
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
	//如果链表长度大于8 就转换为红黑树结构
                        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;
                }
            }
            
           //获取新建节点的值,赋予put方法的value,并返回旧的value
            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) //当梳理大于threshold时候,会进行扩容。
            resize();
        afterNodeInsertion(evict);
        return null;
    }

//modCount和size都表示key-value个数的总和。
//threshold = capacity*loadFactor;
//capacity就是指HashMap中桶的数量。默认值为16
//loadFactor译为装载因子。装载因子用来衡量HashMap满的程度。loadFactor的默认值为0.75f。
//计算HashMap的实时装载因子的方法为:size/capacity,而不是占用桶的数量去除以capacity。

下面是图解,以便帮助读者更加直观的理解。

在这里插入图片描述

put方法中用到的方法

resize(); //重新计算table长度
newNode(hash, key, value, null); //table索引出没有链表,新建链表
TreeNode<K,V> extends LinkedHashMap.Entry<K,V> //红黑树结构对象
((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);//将数据放入红黑树中
treeifyBin(tab, hash); //将链表结构转化为红黑树结构
afterNodeAccess(e); //没有任何操作
afterNodeInsertion(evict);//没有任何操

get方法

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

    /**
     * Implements Map.get and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @return the node, or null if none
     */
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) { //如果hash所在索引的table存在数据
            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) //如果此处为红黑树结构,就按照树查找节点
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {//循环遍历列表,知道找到相应的节点。
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

get中用到的方法

((TreeNode<K,V>)first).getTreeNode(hash, key);

遗留问题:
hashMap中阈值设计理论扩容运算红黑树数据结构

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值