hashmap底层代码解读 put

put—第一次put一个值的过程

  • 说点杂的

    首先需要注意的是,我们所说的hashmap的默认容量为16,并不是指的实例化后的hashmap容量为16,实例化后的hashmap没有任何值设置(虽然有默认值,但是数组啥的都还没创建没任何意义)。

    实例化一个hashmap,debug后发现map1并没有任何的属性。

    	Map<String,Object> map1 = new HashMap<>();
    

在这里插入图片描述

  • put一个值的过程

    	public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }
    

    我们来看一下put方法

    	public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }
    

            第一步获取hash码(注意这个hash码是用来)
            首先调用了hash(key)来计算hash值。如果是key是空,hash码就是0,否则先将key的hash码右移16位补零,再进行^运算得到hash值。(key的hash码根据key的类型而不同,这里是string,则调用string类的hashcode方法)

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

            第二步调用putval方法存值

            首先看一下属性

    	//这里hash已经算出,key, value就是我们传入的键值对
     	putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict)
    	//putval()方法内
    	//底层实现用的数组就是这个tab,p是具体的存放的值,n为数组长度,i为数组下标
    	//node节点属性(final int hash;final K key;V value;Node<K,V> next;)
    	Node<K,V>[] tab; Node<K,V> p; int n, i;
    	
    	//putval()方法内
    	//(第一次调用,tab为null,调用resize进行数组的初始化)
    	if ((tab = table) == null || (n = tab.length) == 0)
    		//请先记住这个n最终值为16 
            n = (tab = resize()).length;
        -----------------------------------------
        //进入resize()方法内
        
        Node<K,V>[] oldTab = table;//初始为null
        // 由于oldTab=null, oldcap容量为0
        int oldCap = (oldTab == null) ? 0 : oldTab.length; // 0
    	// oldThr阈值为0
        int oldThr = threshold;
        int newCap, newThr = 0;
    	
    	//旧容量比0大的时候
    	if (oldCap > 0) {
           ...
        }
        else if (oldThr > 0) // initial capacity was placed in threshold
            ...
        else {               // zero initial threshold signifies using defaults
        	//都为0的时候,也就是第一次进来,设置新容量为DEFAULT_INITIAL_CAPACITY也就是16
        	//设置新的阈值为DEFAULT_LOAD_FACTOR*DEFAULT_INITIAL_CAPACITY 也就是0.75*16=12
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        //设置当前阈值为新阈值的值,12   
        threshold = newThr;
        //实例化node数组,数组大小为newCap,16  这里数组的初始化创建就完成了,也就是n为什么为16
    	Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    	
    	---------------------------------
    	//回到putval()
    	// (n - 1) & hash算出下标,i就等于这个值,n-1是最大下标保证了&后的值不会超出这个数
    	// p就是对应下标的node节点,也就是tab[i], p为null说明该下标没有hash碰撞
    	// 直接设置当前tab[i]的node信息为 hash, key, value(也就是我们一开始传入的值)
    	if ((p = tab[i = (n - 1) & hash]) == null)
    		tab[i] = newNode(hash, key, value, null);
    	else {
    			//这里会根据hash碰撞个数的大小分为,链表跟红黑树  第一次put用不到
    			//第一次put的时候还只是个node类型的数组!!!!!
            ...
        }
        return null;
        
    

    到了这,第一个put就完成了

put—hash碰撞 待会写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值