HashMap面试常问问题

最近在准备秋招面试,集合知识的储备在面试过程当中必不可少,虽然如今已经到了jdk11,可是好多公司暂时仍是jdk.1.8,而且jdk.1.8的新特性,在HashMap这里是一个大突破web

  • jdk1.8中红黑树的加入面试

  • jdk1.7变为链表的头插法以及jdk1.8的尾插法区别数组

  • concurrentHashMap的出现缓存

因此由HashMap进入,能够问关于线程高并发的安全问题引入到并发锁的对比,或者能够由数组,链表到达红黑树引入数据结构的问题。可见HashMap的基础 直接决定了会不会有下面问题的扩展,掌握这个势在必得。
不少人懂这个的原理,可是心中的理解表达不出来,这样子在面试中真的很亏。
下面总结了常见的HashMap的面试问题,下面直接附加有答案,感受本身没有把握的能够直接背过。安全

1、什么是HashMap?

HashMap是一个用于存储Key-Value键值对的集合,每个键值对也叫作Entry。这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干,数组每个元素的初始值都是Null。这些就是HashMap的定义了。数据结构

点到为止,有的面试官不喜欢说的过多。若是想要输的多一点,,能够参考文末的总结多线程

2、你为何用到它?

HashMap能够接受null键值和值,而Hashtable则不能;
HashMap是非synchronized,因此相对而说,HashMap很快;
以及HashMap储存的是键值对,以一种数据之间的对应关系。并发

3、你知道HashMap的工做原理吗?

这时候慢慢的进入集合的问题状态了,准备好面对10分钟左右吧app

HashMap是基于hashing的原理,咱们使用put(key,
value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。svg

当咱们给put()方法传递键和值时,咱们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。”这里关键点在于指出,HashMap是在bucket中储存键对象和值对象,做为Map.Entry。

4、你知道HashMap的get()方法的工做原理吗?

首先根据对象的Hash值进行数组方面的寻找,而后找到这个数组以后,判断key是否是惟一,若是key惟一,则直接返回,若是不惟一,则使用equals进行值的判断,最后返回数据。

5、当两个对象的hashcode相同会发生什么?

这个问题基本上就是分界点了

一些面试者会回答由于hashcode相同,因此两个对象是相等的,HashMap将会抛出异常,或者不会存储它们。
若是以前的问题回答的好,面试官的印象比较好,可能会提醒他们有equals()和hashCode()两个方法,并告诉他们两个对象就算hashcode相同,可是它们可能并不相等。
若是掌握的不太好,一些面试者可能就此放弃。那下面的问题也就不了了之了,等于放弃了一个很好的机会。
而这个问题的答案是:由于hashcode相同,因此它们的bucket位置相同,‘碰撞’会发生。由于HashMap使用链表存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在链表中。这个时候要理解根据hashcode来划分的数组,
若是数组的坐标相同,则进入链表这个数据结构中了,jdk1.7及之前为头插法,jdk1.8以后是尾插法,在jdk1.8以后,当链表长度到达8的时候,jdk1.8上升为红黑树,

这样说,无疑是直接的加分项。有的面试官直接跳入数据结构,有的会直接继续挖掘。

6、若是两个键的hashcode相同,你如何获取值对象?

当咱们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,而后获取值对象,若是有两个值对象储存在同一个bucket,将会遍历链表直到找到值对象。找到bucket位置以后,会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。

【完美的答案!】

请注意:

许多状况下,面试者会在这个环节中出错,由于他们混淆了hashCode()和equals()方法。

由于在此以前hashCode()屡屡出现,而equals()方法仅仅在获取值对象的时候才出现。

一些优秀的开发者会指出使用不可变的、声明做final的对象,而且采用合适的equals()和hashCode()方法的话,将会减小碰撞的发生,提升效率。

不可变性使得可以缓存不一样键的hashcode,这将提升整个获取对象的速度,使用String,Interger这样的wrapper类做为键是很是好的选择。

7、若是HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?

【问到这个问题以后,要及时的意识到面试官要把你往线程安全的方向引入了,作好准备。】

默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类(如ArrayList等)同样,将会建立原来HashMap大小的两倍的bucket数组,来从新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫做rehashing,由于它调用hash方法找到新的bucket位置。

8、你了解从新调整HashMap大小存在什么问题吗?

你可能回答不上来,这时面试官会提醒你当多线程的状况下,可能产生条件竞争(race condition)。

当从新调整HashMap大小的时候,确实存在条件竞争,由于若是两个线程都发现HashMap须要从新调整大小了,它们会同时试着调整大小。在调整大小的过程当中,存储在链表中的元素的次序会反过来,由于移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在头部,这是为了不尾部遍历(tail traversing),原数组[j]位置上的桶移到了新数组[j+原数组长度]。若是条件竞争发生了,那么就死循环了。

(若是线程方面的知识储备还不错,那这个时候,你能够质问面试官,为何这么奇怪,要在多线程的环境下使用HashMap呢?,不直接使用concurrentHashMap)

而后,恭喜你,你的线程面试开始啦!!!


若是读者对这个问题感兴趣,能够再来看看这些问题设计哪些知识点:
● hashing的概念
● HashMap中解决碰撞的方法
● equals()和hashCode()的应用,以及它们在HashMap中的重要性
● 不可变对象的好处
● HashMap多线程的条件竞争
● 从新调整HashMap的大小


总结

HashMap的工做原理 HashMap基于hashing原理,咱们经过put()和get()方法储存和获取对象。当咱们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,经过键对象的equals()方法找到正确的键值对,而后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每一个链表节点中储存键值对对象。 当两个不一样的键对象的hashcode相同时会发生什么? 它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。