HashMap底层实现原理

HashMap底层实现原理

本文中描述的HsahMap实现是基于JDK1.8.x版本的

第一:存储方式

HashMap从命名上讲,存在一个Hash, 所以底层其实使用的是散列Hash的方式来存储内容的。而散列Hash具有一些弊端 (当发生Hash碰撞后,不同的解决冲突的办法会造成不同的效率损失,所以效率不稳定),我们发现单纯使用散列Hash存储数据, 是有弊端的,所以JAVA使用数组来实现散列Hash过程并将碰撞后的数据以链表的形式来保存。

于是我们得到了HashMap的底层数据存储方式:数组(实现散列Hash)+链表的方式来保存数据。

**注意:**这里没有结束,因为在链表长度超过一定值以后,链表的定位效率会直线下降,所以需要将链表进化成一种树结构, 叫做红黑树(AVL) ,是一种弱平衡的二叉查找树。这个部分在下文中。

什么是Hash,什么是散列Hash

Hash是一个算法簇,是满足某种条件的算法,我们叫做Hash算法

​ 1.算法结果固定的:固定的输入能得到固定的结果

​ 2.算法过程不可逆的:可以从输入推到出来结果,但是不能从结果推出输入

满足以上两种条件的算法,我们都叫他Hash算法。比如加法就是一个Hash算法

​ 例子:3+5=8,在任何情况下,3+5都等于8,其中3+5是输入,8是结果,我们可以从3+5推算出来结果是8,

​ 但是不能从结果8,推算出来输入就一定是3+5, 也可能是1+7。

什么是散列Hash呢?散列Hash是一种存放数据的方式,他并不是简单的加法或者减法。我们现在给出一系列数据。用这一系列数据举例 7,3,8,32,91,24,53
现在需要将这7个数字,放在某个容器里面。首先,我们使用数组(或者顺序表) 容器来存放这7个数字。
第一步:我们需要创建一一个长度至少是7的数组。然后依次,将数据放在数组中

内容角标
70
31
82
323
914
245
536

这个就是用顺序表来存放数据的方式,但是除了这种存放方式以外,我们还有其他的存放方式,比如链表(不举例了),也还有其他的结构可以存内容,比如树,图,这其中其实我们用的真正保存过程最多的是Hash散列。

Hash散列也是一种存放过程,和数组存放非常像,只不过内容并不是按照数组保存的顺序来保存。

散列过程和线性表过程不同的地方,在于输入的数据,是要根据某种算法来决定这个数据放置在哪个位置上的。而不是根据输入的先后顺序来决定数据应该放在数组的那个位置上。

我们用最简单的算法来处理,求余数。

当前数组长度是7,那么我们用要放置的元素去针对7取余数,这个余数只能是0-6之间。

按照这个过程,我们重新放置7,3,8,32,91,24,53这个内容

内容角标最终位置
700
333
811
3244
9102
2435
5346

我们发现,有几个值的角标算完和之前放置进来的值的角标是一样的,但是数组中这个位置如果已经有数据保存在这里了,就不能将新的数据保存在同一个角标下。

当我要放置91时,发生了Hash碰撞: Hash碰撞(Hash冲突)当我想要放置某个值到某个位置的时候,发现那个位置上已经有值了。这个过程是由于选择的Hash算法针对这两个输入得到的结果是一样的。

注意:发生Hash冲突以后,我们就要想办法解决这个Hash冲突,要不然这个数据,就没有办法放置在容器里面了。

我们通过偏移当前要放置的值,来改变这个值可能的角标。

最终得到的结果如上图所描述的结果。

上面说的解决Hash冲突的过程是一种解决方式,但是JAVA并没有选择这个方式来解决实际发生在HashMap中的Hash冲突

首先,HashMap的底层,也是一个数组,是一个Node的数组,这个Node里面,包含了Key和volue

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
        //此处省略部分实现
        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
    

Node的部分源码见上:HashMap创建的就是这个Node的数组
在这里插入图片描述
通过上图我们知道HashMap实际上使用了拉链法来解决Hash冲突问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值