1.put方法源码:put方法中首先使用hash算法计算出的hash值以及传入的key,value以及其他的两个参数传递给putVal()方法;

alt

2.hash()方法:可以发现hashMap中的hash算法不完全等同于object中的hashCode();key可能会重写了hashCode(); alt

Note:首先会判断key是不是null(说明在hashMap中是支持key等于null的),如果key为null,默认其hash值为0;如果key不为null,首先会调用key这个对象的hashCode()赋值给了成员变量h,并且h和(h右移16位的值进行异或运算);

解释:int类型是一个32位的值,右移16位的目的是为了使得hash值得低16位值和高16位值都能够参与运算,于是就得到了一个比较均匀的值;

3.putVal()方法:

alt

alt

解释:首先这个方法中传入了hash值,key,value(主要的几个参数),并且创建了临时变量tab ,节点p, 临时长度n; 将hashMap的table数组赋值给tab,table的长度赋值给n,如果tab为null,那么就使用resize方法扩容,并且修改n,修改tab; 使用(n-1)&hash的方式获得数组的下标值,并且把此位置的数组的位置赋值给节点p,如果节点p是null,说明此位置的没有值,这个位置恰好是table[i],于是数组中的这个位置就新创建了节点; 否则:table[i]处的位置原本就有值得的话:首先创建临时节点e,以及临时键变量k;如果节点p的hash值恰好是我们之前传入的hash值得话,并且键相同的,那么让节点p赋值给节点e;(其实之前的节点p就是table数组的制定槽位的链表的表头,于是e就是表头。)否则如果节点p是一个树节点的类型时,那么就先强制转换p节点的类型为树节点,接着使用putTreeVal方法在红黑树中加入此节点;否则:就说明是链表的形式,于是为了在链表的最后一个位置插入节点,使用for循环,定义变量bincount = 0,让e为节点p的下一个节点,如果节点e为null,说明是链表的尾部,于是在此位置,new一个新的节点添加进入;添加完成之后会盘点bincount是否是大于了树化的阈值,如果大于等于树化的阈值(阈值是7,但是实际上包括table中的对应的链表的表头,总共会在8个节点的时候树化,使用treeify(table,hash)方法树化变为红黑树)。如果,在链表范围内发现哈希值相同,key相同,于是就会结束循环;p = e ,通过这种方式不断地使得e能够永远的指向节点p的下一个节点。