设计规范理解
- 有时候我们很容易看出一种限定条件的原因,如防止数组越界而占用其他内存空间而加个if限定i大小等我们初学就一直碰壁而形成条件反射的这种设计规范,但有些限定条件(有些有明显在代码中写入:hashmap的resize限定为2的倍数,有些只是告诉你依据规范要这样实现:euqals和hashcode)未能在我们脑海中以形成条件反射的形式告诉我们原因,此时我们光看源码是难以反推导出原因的,我们需要返回去看一个方法/类设计最初的思想是什么
- 其实阅读源码的作用可是是为了更好的调用接口、了解临界条件和理解类之间的层次关系,或者修改其实现达到更高的效率,但是有一些源码实现在不同的条件下仍可运行,可能会产生不同于你想要的逻辑的结果(euqals和hashcode),我们可以专门设计实现去约束他,但是必然会牺牲效率,也丧失了对于极端情况的自由度(hashmap的resize限定为2的倍数),不如作为一个编程规范来的理想,而且,此时只看源码也只知道他规定了这样,但是不知道原因,也难以更好地理解你想学地东西地初衷,若是想要更好地理解一些可能像是约定的设计宗旨和设计细节,要专门阅读其设计的规范文档,以了解为何要这样限定,此时只看源码就不能反推出原因了。
如果equals相等,hashcode一定相等。所以如果equals重写,hashCode也要重写。
equals是我们逻辑上判断两个个体是否相同的函数,如果我们需要的情况下下判断两个体在当前相同,那我们应该把他们当作不同存储空间的两个相同实例
hashcode的目的是通过计算来快速获取我们想要的实例,因此若是逻辑相同的情况下,我们将他们视为相同,在不考虑哈希冲突的情况下,我们甚至可以一个代替另一个(或者不处理),不需要链表。
两者逻辑目的相同,因此若想符合两者的定义,需要符合上述约定
我们不能从putVal等代码层入手,因为是在上面这种条件下我们才有这种结果(逻辑相同即为相同),不同的条件下依据相同的该份代码会有不同的结果,因此我们不能从代码层入手来反证明上面的条件,只能从条件经由代码得出唯一结果
若是key.equals相等而hashcode不等,则当前场景下需要逻辑相等的对象将被作为两个不同种类的对象存储了,相等的方式变成了物理相同才相同了,与定义不符。(因为equals若是同一个对象,则除非用随机数来判断equals不然肯定相同)
为何HashMap的数组长度一定是2的次幂
我们计算出hash值后由h & (length-1)来确定
作用在于限制算出来的hash能在数组length下存储,可以不是2的次幂,但是我们设计hashcode的时候已经很难避免不同对象同一个hash值了,为了hash更具有他通过计算高速定位的作用,我们应该做到在数组范围内不同hash值要有不同的的地方存储,不能使得不同的对象不同的hash值还因为存储问题需要冲突处理,若是出于节省数组空间的角度,最高位固定,从数组整体长度来看,后面的也减少不了太多,而若是最高位变0则又是基于2的倍数的)
这也是由定义到代码到结果的,单纯研究代码也是可以有不同的结果,得不出这样做的意义
当然,length是2还和resize时对于oldcap计算得到得index的复用在nextab中复用减少计算量的作用,这是能直接通过代码看到的,但是我仍觉得上面的原因为需要为2的次幂的主要原因,因为这是hash表设计规范时的定义,复用只是多出来的红利。