HashMap原理

37 阅读3分钟

HashMap底层使用的是一个数组 +(链表或红黑树的形式)。

首次put

在我们首次put元素的时候HashMap中会创建一个长度为16(默认值)的数组,如果不为默认值那么它值就为 >=我们传入值的偶次幂(保证数组长度-1&上HashCode值的时候不会把HashCode值给改动(尽量保证后n位置)) ,并且使用扩展因子*数组长度就得到我们下一次需要扩容的大小,然后将我们的Key执行Hash后&数组的长度减一 这样就得到了我们Key在数组元素的下标。

再次put

在我们再次put的时候如果我们的 Key执行Hash后&数组的长度减一 得到存储的下标位置如果当前的下标中没有元素那就直接存入。如果当前的下标中存在元素那就就去遍历这个链表元素去寻找与我们当前添加Key的Hash相同并且equals也相同的节点,找到后就会将其值覆盖。如果没有找到那么就将put的元素添加到这个链表的末尾。put后对数组容量大小做一个判断:如果当前达到了扩展值就会调用resize方法对其进行扩容,扩容实质是对当前的大小进行一个左移运算(*2)并且使用扩展因子计算得到的数组扩容容量也进行一个左移运算(*2)。然后创建扩容后的数组,再遍历旧数组重新计算【(数组长度-1)& hash值】位置后添加到新数组对应的下标。

扩容

如果当前达到了扩展值就会调用resize方法对其进行扩容,扩容实质是对当前的大小进行一个左移运算(*2)并且使用扩展因子计算得到的数组扩容容量也进行一个左移运算(*2)。然后创建扩容后的数组,再遍历旧数组重新计算【(数组长度-1)& hash值】位置后添加到新数组对应的下标。

获取元素

对传入的Key进行 Hash运算后&数组长度-1 得到在数组中的下标如果没有值着返回null,如果有值就遍历下标中的链表找到与我们与传入Key的Hash值相同并且equals方法也相同的节点后将他返回。

为什么重写equals方法必须要重写hash方法

从HashMap的底层原理我们知道了HashMap判断需要依靠Hash方法以及equals方法。如果我们重写了equals方法后,这个类就没有办法很好的与一些集合类配合。重写equals方法后可能让一个hash值不相等的对象equals却相等(人为)的情况,所以就有了重写equals方法就需要重写hash方法的规约出现。