文章目录
一、HashMap实现原理
你看过HashMap源码嘛,知道原理嘛?
HashMap采用Entry数组来存储key-value对,每一个键值对组成了一个Entry实体,Entry类实际上是一个单向的链表结构,它具有Next指针,可以连接下一个Entry实体。
只是在JDK1.8中,链表长度大于8的时候,链表会转成红黑树!
为什么用数组+链表?
数组是用来确定桶的位置,利用元素的key的hash值对数组长度取模得到.
链表是用来解决hash冲突问题,当出现hash值一样的情形,就在数组上的对应位置形成一条链表
hash冲突你还知道哪些解决办法?
比较出名的有四种:开放定址法、链地址法、再哈希法、公共溢出区域法
-
开放地址法
从发生冲突的那个单元起,按照一定的次序,从哈希表中找到一个空闲的单元。然后把发生冲突的元素存入到该单元的一种方法。开放定址法需要的表长度要大于等于所需要存放的元素。 -
再散列
当发生冲突时,使用第二个、第三个、哈希函数计算地址,直到无冲突时。缺点:计算时间增加。 -
链接地址法的思路是将哈希值相同的元素构成一个同义词的单链表,并将单链表的头指针存放在哈希表的第i个单元中,查找、插入和删除主要在同义词链表中进行。在java中,链接地址法也是HashMap解决哈希冲突的方法之一。
-
公共溢出区域法
将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数据统一放到溢出区。
我用LinkedList代替数组结构可以么?
答案很明显,必须是可以的。
既然是可以的,为什么HashMap不用LinkedList,而选用数组?
因为用数组效率最高!
在HashMap中,定位桶的位置是利用元素的key的哈希值对数组长度取模得到。此时,我们已得到桶的位置。显然数组的查找效率比LinkedList大。
既然是可以的,为什么HashMap不用LinkedList,而选用数组?
因为采用基本数组结构,扩容机制可以自己定义,HashMap中数组扩容刚好是2的次幂,在做取模运算的效率高。
而ArrayList的扩容机制是1.5倍扩容,那ArrayList为什么是1.5倍扩容这就不在本文说明了。
二、HashMap在什么条件下扩容
HashMap在什么条件下扩容
如果bucket满了(超过load factor*current capacity),就要resize。
load factor为0.75,为了最大程度避免哈希冲突
current capacity为当前数组大小。
为什么扩容是2的次幂
HashMap为了存取高效,要尽量较少碰撞,就是要尽量把数据分配均匀,每个链表长度大致相同,这个实现就在把数据存到哪个链表中的算法;这个算法实际就是取模,hash%length。
但是,大家都知道这种运算不如位移运算快。
因此,源码中做了优化hash&(length-1)。
也就是说hash%length==hash&(length-1)
位运算比较高效,当b为2的n次方时,有如下替换公式:
a % b = a & (b-1)(b=2n)
即:a % 2n = a & (2n-1)
为什么为什么要先高16位异或低16位再取模运算
hashmap这么做,只是为了降低hash冲突的几率。
比如,当我们的length为16的时候,哈希码(字符串“abcabcabcabcabc”的key对应的哈希码)对(16-1)与操作,对于多个key生成的hashCode,只要哈希