alt

解释:

情形一:当使用hashMap的无参构造器时,由于无参构造器之中没有做额外的工作只是设置了一下负载因子,oldTab == null ,于是oldcap为0;并且oldThr也就为0;

情形二:使用hashMap的有参构造时,oldcap为0,oldThr不为0;

定义了旧的容量,旧的阈值,新的容量,新的阈值;最终的目的是得到新的阈值赋值给成员变量,得到新的容量创建一个新的数组,然后使用table执行新的数组,这就是这个代码的实际目的;其中源码中比较复杂的if语句就是在拷贝数据,使得数组能够从旧的hashMap中拷贝到新的数据结构当中。

其中主要看上半部分的if语句:首先判读oldcap>0,也就是table已经有值了,在真正扩容之前首先会做一次判断,如果旧的容量已经大于等于最大容量了,那么会修改阈值为Integer.Max_VAlue;否则才会真正的扩容,新的容量等于旧的容量左移一位也就是乘以2,也就是新的容量小于最大容量时,并且旧的容量大于16,就让新的阈值也扩大2倍;

(由于使用了if-elseif_else语句,也就表明了只会进入其中一个代码块,第一种情况下主要保证了table不null的情况下,所以elseif以及else中的情况主要是hashMap被初始化的一种情况;)

如果使用了有参构造,在构造的时候传入了初始化的容量,那么阈值则大于0,那么就让旧的阈值等于新的容量;

如果使用了无参构造,那么就会走到最后一个else语句,也就是oldcap=0,oldthr = 0;那么就会赋值一对默认值:默认的容量为16,默认的阈值为负载因子乘以默认的容量;其中负载因子为0.75;

中间的方法中没有给newThr新的阈值赋值,于是新的阈值 = 新的容量乘以负载因子得到的阈值,但是会先进行判断此阈值,如果这个被计算出来的阈值小于最大容量,并且新的容量也小于最大容量,那么就让被计算出的阈值等于newThr(新的阈值),否则就赋值Integer.max_value;当这些工作全部完成之后就接着执行数组中的内容重新赋值的工作;(最后的工作比较复杂)

alt

alt alt

resize()这个方法出现的位置主要在:

1.putVal()中如果table是null的话,也就是未初始化时就会使用resize()方法初始化;

2.以及在完成节点新增之后,hashMap的size大于hashMap的阈值时,resize();

3.树化方法中treefiyBin()方法中,如果table.length小于64时 resize();

这三个条件下在方法中也存在不同的体现:

1.条件1未初始化的原因:原因在于hashMap的构造器中比较简单除了赋值了一个负载因子,以及一个阈值此外没有做其他的事情,这就是hashMap为啥创建对象的原因;所以table这个对象也不是直接创建出来的,而是在调用resize()方法的时候才去new;

alt 解释:判断table如果为null,或者数组的长度小于64,那么先不树化而是先扩容(扩容的代价比树化的代价低)

额外的红黑树节点类的源码:树节点类继承了hashMap.Entry<K,V>;

alt