详解HashMap的存储结构与hash冲突

面试的时候,我想大家都会被问到关于HashMap的问题,因为这个数据结构可以说是java比较复杂的了,ArrayList与LinkedList都比较简单了,这里就不详说了,单说一下HashMap。

在说HashMap之前,首先说一下,LinkedList,LinkedHashSet,LinkedHashMap这些数据结构全是链表,并且是双向链表,就是说可以从前往后找,也可以从后往前找。HashSet与HashMap是一回事,请大家切记,只不过是存储HashSet的时候,value是一个虚拟机的object对象,其他的操作与hashMap一模一样。

说完这些之后,可以看一下源码,有两个重要的属性,一个是Node[]数组,一个是Node,并且这个Node是一个链表,这里大家切记,HashMap中的内部类不是Entry,而是Node,Node实现Entry接口,Node中有四个属性,hash, key, value,next,其中next就是用来解决hash冲突的。其中hash就是计算key的hash值。而添加元素定位的时候也是通过这个hash来定位的,定位的坐标就是array.length - 1 & hash,就是数组的长度-1与hash值做与运算得到的值。这里会有人担心,这样算出来的值万一比数组的长度大呢?这个不必担心,因为是做的与运算,只会把array.length-1与hash值末尾的一部分做运算,其他的都是0,而剩下的这部分作与运算就一定会比array.length-1小了,而最大也只能与array.length-1一样大。HashMap中value是没有任何作用的,只是用来作为一个附加的存储的值,不会参与任何的运算。

以上说了一下HashMap中的存储结构,现在说一下经常被问到的一个问题,hash冲突。首先,hashmap添加元素时,并不是在数组上挨个添加的,而是通过key的hash与array.length -1作与运算得到一个坐标值,所以这样的数组也被称为散列表。hash冲突是指添加元素时,数组中通过hash定位到的位置中已经有了元素,这个时候,分为两种情况,key一样与key不一样,这个时候比较Key就用key的直接值,而不是用hash值作比较了。如果key一样,则直接替换到掉旧的节点即可,如果key不一样,表示这是两个完全不同的Node,这时就是hash冲突。因为定位到的坐标一样,但是存储的key不一样,就是说值是不能直接替换的,但是存储位置被占用了,这个时候怎么办呢?这个时候Node中的next就发挥作用了,Node被设计成链表也是这个原因,当定位到的坐标是一样的时候,但是key不一样,则会将后来添加的元素链接到原来元素的next上,成为一个链表。如果之后添加元素还有冲突,就再在原来链表的末尾添加节点。这就是java中解决Hash冲突的办法:数组加链表的设计。

你可能感兴趣的:(JAVA,HashMap,hash冲突,存储结构,面试,源码)