put()
1.判断key是否为null,如果为null,调用putlForNullKey,将key插入到数组下标为0的位置
2.调用hash()方法计算key的hashcode,得到hash值
3.调用indexFor()方法进行取模运算,得到元素的下标位置
1.indexFor方法为:h&(length - 1)
2.使用与运算,计算速度更快,因为二进制运算比十进制运算效率更高(十进制运算还需要将二进制转化为十进制)
3.length之所以要设定为2次幂,就是为了这个indexFor方法服务
4.可以让散列更加均匀,length-1的最后一位为1,因此进行与运算时,可以散列到奇数和偶数的下标位置,如果对length直接取模,由于length为2次幂,所以最后一位一定为0,所以与运算的结果一定是偶数,这也就导致奇数下标的位置不能被散列到。
4.依次和该下标位置上的链表中的node节点比较key是否相等
e.hash == hash && ((k = e.key) == key || key.equals(k))
首先判断e.hash==hash是因为不同的key值也可能被散列到同一个位置,因此首先判断hash值,如果不相等则两个key肯定不等
如果相等,再通过==和equals比较是否相等,之所以要先判断hash值是否相等,<b><font color="#c41230">是因为equal()很耗性能,因此先判断hash值能够提高效率</font></b>
重写了hashcode()方法就必须重写equals方法
5.如果相等,更新value值,如果不相等,使用头插法(1.7)/尾插法(1.8)将entry(1.7)/Node(1.8)插入到链表中
get()
和put()方法类似,获取到桶的下标,再在链表上查找key值,再获取key对应的value值
resize()
当hashmap中的元素个数超过数组大小*loadFactor时,就会进行数组扩容
扩容时,令 capacity 为原来的两倍。
1.7时,需要new 一个新数组,并对旧数组上的所有元素进行indexFor()操作确定下标地址,这一步很费时,<b><font color="#c41230">1.8时只需判断hash值的左边新增的那一位是否为1,即可判断此节点是留在原地lo还是移动去高位hi,如果为1,则移动去高位,否则不变</font></b>
1.7时,扩容的时候可能出现死循环,1.8没有这个问题
构造方法
在第一次put()的时候,数组才初始化
<b><u><font color="#c41230" style="">数组的长度为大于指定值的最小二次幂</font></u></b>
数组默认大小为16