概述:我们都知道,要查找一个元素,如果是顺序查找,那么时间复杂度就会达到O(n),比如:顺序表,也有可能达到O(logn),如:平衡树。那么要想更快,我们就可以考虑另一种数据结构,它可以达到实践复杂度为O(1),如:HashMap。我们在面试过程中HashMap出现的次数也非常多,接下来,来看一下HashMap的一些考点。

1. 什么是HashMap?

HashMap是一种key-value模型,具有映射关系,通过key值可以找到 value值,并允许使用null值和null键,HashMap不保证映射的顺序,特别是它不保证该顺序恒久不变。

2.HashMap是如何解决底层冲突的?

不同关键字通过相同哈希方式计算出相同的哈希地址,该种现象称之为哈希冲突或者哈希碰撞。如何解决冲突呢?在JDK1.8开始,HashMap是基于数组+链表+红黑树来进行实现的。

解决冲突的方式主要有闭散列和开散列。

JDK1.8中,如果产生冲突,采用开散列进行处理,会在对应位置的下标的单链表中插入冲突的元素,如果value值相同,进行数据更新,如果不同,插入这个元素。如果一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提高速度。

3.简述HashMap的工作原理

通过hash的方法,我们使用put个get存储和获取对象。

存储对象时,我们将K/V传给put方法时,它调用k对象的hashCode计算hash从而得到bucket(数组下标)位置,当发生冲突时,如果value值一样,则会替换接的key的value,value不一样则新建链表节点进一步存储。HashMap会根据当前的bucket的占用情况自动调整容量。获取对象时,我们将k传给get,get调用k对象的hashCode计算hash从而得到bucket位置,并进一步调用k对象的equals()方法确定键值对。

如果发生碰撞的时候,HashMap通过链表将产生碰撞的元素组织起来,在java8中。如果一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提高速度。

4.HashMap的负载因子

HashMap的默认负载因子为0.75,如果超过0.75,会重新resize一个原来长度两倍的Hashmap,并且重新调用hash方法,对原来的数据进行重新hash。

5.HashMap中的equals()和hashCode()都有什么作用?

通过对key的hashCode进行hash,并计算下标,从而获得bucket的位置。如果产生碰撞,则利用key.equals()方法去链表或树中去查找所对应的节点,另外也是为了保持数据一致性。 

6.HashMap和HashTable的区别有哪些?

①HashTable是线程安全的,HashMap是线程不安全的。

②HashMap可以使用null作为key,不过建议尽量避免这样使用。HashTable则不允许使用null作为key。

③HashMap的初始容量为16,HashTable初始容量为11.

④HashTable计算hash是直接使用key的hashCode对table数组的长度直接进行取模,HashMap计算hash是对key的hashCode进行了二次hash,以获得更好的散列值,然后对table数组长度取模。

7.使用场景

非并发场景使用HashMap,并发场景使用HashTable,但是推荐使用CurrentHashMap(锁粒度更低,效率更高)。

另外在使用HashMap时要注意null值的判断,HashTable也要注意防止put null key和nullvalue