以下内容第一遍全按照记忆来,会有一些不太全的地方。
1.首先构造有两种:①带参数构造,如hashmap(10),此时底层会将输入的参数进行多次位运算(转换成后几位全是1的,比如111,1111),扩容的时候就在二进制转化为10进制的时候再加上1即可。也就是说,会就近返回一个2的次幂,这个才是数组的大小。比如说传入10,会返回16,传入15也是16,传入17会返回32。以此类推。注意:此时仅仅只是将改容量大小赋值给threshold,并没有创造数组,也就是说不管你传入几,我都先跟你存着,等你第一次put元素进去的时候我再给创建数组
②无参构造,内部什么也不做,仅仅只是定义一个负载因子,这个因子等于0.75,为什么等于0.75,因为这是开发团队大量实验出来的结果,这个能保证数组得到充分的利用。
2.第二步put方法:
①如果原本没有值得话
步骤1:首先会用hash算法去取得key对象的hash值,也就是用对象的hashcode的高位和低位进行位运算(将整个hashcode右移16位,在和原值进行异或),这种算法能够让最终得到的hash值更加分散,当然这个算法也是大量实验得出来的。
步骤2:判断当前数组是否为null,或者长度为0,如果是,会立马给数组进行扩容,并且直接扩容为16
步骤3:用得到的hash值与n-1进行&操作,得到最后的位数的二进制编码值,转换为十进制就是索引值,当然也可以理解为实际上是对象的hash值对n取模。
步骤4:判断当前索引位置上的是否有元素,没有则直接赋值。
步骤5:改变次数加1,容量size+1,并判断size是否达到阈值,如果达到就会进行扩容操作,每次扩容为原来的两倍。
②如果原本数组不是null的情况下
步骤1:同上
步骤2:不为空跳过不走
步骤3:同上
步骤4:为空,同上,不为空,则跳过
步骤5:首先判断新对象a的hash值是否和当前对象b的hash值相同,如果相同,继续比较,看两者的引用是否相同或者两者是否equals,如果达到条件,说明其key是一样的,直接进行值的更新
步骤6:如果两者不一样,则会出现两种情况,要么放到链表上,要么放到红黑树上。首先判断是否为红黑树节点,如果是,就会进行红黑树的遍历操作。(此处略过,等复习了treeset再总结)
步骤7:如果该节点不是红黑树,就去遍历链表,使用无限循环,首先看该节点的下一位是否为null,如果是直接在后面加上新节点。并且判断该链表是否达到8,如果达到8,就要将此链表转换为红黑树来增加查询的效率。(我记得好像还有一层判断,如果数组长度超过了64,才会变成红黑树,否则不到64的话就直接进行扩容),并且跳出循环
步骤8:如果下一个子节点不为null,则进行hash值得比较(和上面一样),一样就刷新值并且跳出循环,不一样就继续下一轮循环
步骤9:改变次数加1,容量size+1,并判断size是否达到阈值,如果达到就会进行扩容操作,每次扩容为原来的两倍。