用几个问题来理解HashMap

在Java面试时,HashMap被问到的机率还是很大的,当面试管问:“你对HashMap的理解有多少”时,你是否会呆滞一下。也许你有看过HashMap相关的介绍,甚至有看过源码并分析过。

但因时光流逝,对HashMap的理解就变成了碎片记忆,思路混乱,不知从何说起。我以面试官的身份进入一问一答。面试官的习惯就是刨根问底,因为是面试回答,所以我这边对于回答并没有太详细讲解,毕竟面试中,哪有那么多时间听你讲解细节。把HashMap拆成几个问题来记忆,也许会更容易理解。

用几个问题来理解HashMap

1、你对HashMap的理解有多少?

HashMap是一个散列表,它存储的内容是Key-Value键值对映射,它继承AbstractMap类,并且实现了Map,Cloneable,java.io.Serializable可序列化接口

2、什么叫散列表?

散列表也叫哈希表,是根据关键码值(key value)而直接进行访问的数据结构,也就是说,它通过关键码值映射到表中的一个位置来访问记录,以加快查找的速度。

这个映射函数叫做散列函数,存放记录的数组叫做散列表。

用几个问题来理解HashMap

3、HashMap如何解决哈希冲突?

HashMap采用“拉链法”解决哈希冲突。拉链法又叫链地址法,是把具有相同散列地址的关键字(同义词)值放在同一个单链表中,称为同义词链表。有m个散列地址就有m个链表,同时用指针数组T[0..m-1]存放各个链表的头指针,凡是散列地址为i的记录都以结点方式插入到以T[i]为指针的单链表中,T中各分量的初值应为空指针。

4、拉链法的优缺点是什么?

拉链法的优点是:拉出一个动态链表代替静态顺序存储结构,可以完全避免哈希函数的冲突。缺点是链表的设计过于麻烦,增加了程序的复杂度。

5、影响HashMap性能的参数有哪些?

有两个参数影响HashMap性能。一个是初始容量(initialCapacity),一个是加载因子(loadFactor)。

6、你能介绍一下这两个参数的作用吗

容量是指哈希表中的桶数量,初始容量是哈希表在创建时最初的容量,默认为16。我们在初始化HashMap时可以通过构造函数进入修改初始容量值

加载因子是哈希表在其容量自动增加之间可以达到多满的一种尺度,默认为0.75。当哈希表中的条目数超出了加载因子乘于当前容量值时,则会对哈希表进行rehash操作,从而哈希表将扩展至大约两倍的桶数

7、那怎么优化HashMap?

减少rehash操作就是HashMap的最大优化,当我们在业务逻辑开发时,能预测出这个业务会使用大概多少的哈希桶。比如我们预计需要20个桶数,而HashMap的初始容量是16,而rehash之前的最大桶数为16*0.75=12。20远远大于12,所以必定会进行rehash一次,rehash后的容量为16*2=32。32*0.75=24>20=true,也就是当我们业务预计20个桶数时,不修改初始容量的情况下,HashMap会进行一次rehash操作。rehash是重新创建一个新的数组对象并且进行对象转移,并且修改容量大小,这期间的性能消耗很大。因此,减少rehash操作就是HashMap的最大优化。

还有对key的值尽量短,避免hashCode冲突时所花费更多的时间进入equals比较,建议采用String,Integer这样的类型作为键。

8、HashMap共有几个构造函数?

HashMap共有四个构造函数,

一个是不带参数的构造函数,

一个是可以改变初始容量大小int参数的构造函数,

一个是可以改变初始容量int参数和加载因子float参数的构造函数,

一个是包含子Map的构造函数。

用几个问题来理解HashMap

9、HashMap扩容时为什么一定是2的幂次

当数组长度为2的n次幂的时候,不同的key算得index相同的几率较小,数据在数组上分布就比较均匀,也就是碰撞的几率小,相对的,查询的时候就不用遍历某个位置上的链表,这样查询效率也就较高了。 反之假如当数组长度为15的时候,hashcode的值会与14(1110)进行“与”,那么最后一位永远是0,而0001,0011,0101,1001,1011,0111,1101这几个位置永远都不能存放元素,空间浪费相当大,并且数组可以使用的位置比数组长度小了很多,使得进一步增加了碰撞的几率,减慢了查询的效率!


分享到:


相關文章: