HashMap面试怎么面?

开发 前端
HashMap是java面试的时候最常问的问题,其中牵扯的知识点很多,很适合考察面试的基础,我反正面试很多家这个问题确实是必问,不准备一番还真不好回答好。
本文转载自微信公众号「Java时间屋」,作者Jack佳。转载本文请联系Java时间屋公众号。
  • 1.HashMap的数据结构:
  • 2.HashMap的hash函数设计:
  • 3.Java1.8的Java1.7对比:
    • 3.1 扰动的次数减少:
    • 3.2 结构变化:
    • 3.3 插入变化:
    • 3.4 扩容的变化:
    • 3.5 扩容的时间变化:
  • 4.HashTable和Collections.synchronizedMap、以及ConcurrentHashMap可以实现线程安全的Map原理:
  • 5.Map集合的顺序:

前言

HashMap是java面试的时候最常问的问题,其中牵扯的知识点很多,很适合考察面试的基础,我反正面试很多家这个问题确实是必问,不准备一番还真不好回答好。

1.HashMap的数据结构:

JDK1.8:数组+链表/红黑树 数据结构原理:链表长度>8&数组大小>=64=》转为红黑树存储;红黑树节点个数<6转为链表。tips:为什么不是小于8是为了防止频繁的结构转换增加开销。那为啥是8呢?发生hash碰撞的几率8次的概率为百万分之6,够了。HashMap的数据插入原理:

重点说明:上面计算数组位置的方法是:通过 (n - 1) & hash计算应当存放在数组中的下标 index ;叫做位运算为啥(n-1)更接近于取模,为啥采用位运算是因为效率高,不存在二进制和十进制的转换。这里在补充一点HashMap初始化数组大小的问题,HashMap数组初始化大小为16,为啥呢?理论上来说2的整数次幂都可以,但是如果是2,4或者8就会有点小,添加不了多少数据就会扩容,影响性能,如果是32或者更大,就会浪费空间。所以16是一个经验值保留下来的。

2.HashMap的hash函数设计:

在HashMap中,首先是通过key的hashcode(32位的int值)然后让hashcode的高16位和低16位进行异或操作。为啥这样设计:1.上面的hash函数也叫扰动函数,主要考虑尽可能降低hash碰撞,越分散越好。

2.算法一定要尽可能的高效,因为这是高频操作,因此采用位运算。

3.因为hashcode的范围是int类型,大概40亿的映射空间,如果只是hashcode,很少会出现碰撞,但是数组和内存是发放不下的,初始大小才16的数组只能进行取模运算/位运算来达到目的。

HashMap的数组长度要取2的整数幂,这样数组长度-1刚好"低位掩码",加上hash函数(扰动函数)降低碰撞。

3.Java1.8的Java1.7对比:

3.1 扰动的次数减少:

java1.8跟java1.7在这里的区别就hash函数里面是java8只扰动了一次,为了效率。java7在这里扰动了四次。

3.2 结构变化:

1.7里面的数组+链表===》数组+链表或红黑树。为什么这样做,前者的查询效率是n后者的查询效率是log2(n),所有当链表数据量大的时候会有效率问题。

3.3 插入变化:

链表的插入方式从头插法改成了尾插法,简单来说就是1.7中是往前面插入,1.8中是往后插入,这样做的目的是为了防止扩容的时候死循环。

3.4 扩容的变化:

扩容的时候1.7是重新hash定位新数组的位置,1.8则是采用更简单的逻辑判断,位置不变或索引+旧容量大小。为什么1.8能这样,计算数组的位置的掩码仅仅只是高位多了一个1。

3.5 扩容的时间变化:

在插入时,1.7先判断是否需要扩容再插入,1.8是插入以后再判断是不是需要扩容

4.HashTable和Collections.synchronizedMap、以及ConcurrentHashMap可以实现线程安全的Map原理:

我们都知道的是HashMap是线程不安全的,1.7版本的时候会产生死循环、数据丢失、数据覆盖的问题,1.8中解决了其中的两个问题,仍然会有数据覆盖的问题,就是多线程并发操作下的值覆盖。如果业务场景中需要线程安全,就要使用线程安全的Map类,一般我们使用的是ConcurrentHashMap。

ConcurrentHashMap:使用的分段锁,降低锁粒度,提高并发度和效率。1.8相对1.7也是提升了效率,成员变量之间使用了volatile修饰,避免了指令重排,保持内存可见。采用的CAS和synchronized结合实现赋值操作,只会锁住当前操作索引节点。

HashTable:直接在操作方法上synchronized关键字,锁住整个数组,效率会很低。SynchronizedMap:内部实现的对象锁实现。效率比HashTable会高点。

5.Map集合的顺序:

HashMap里面是无序的,所以只能循环遍历。LinkedHashMap:有序map,内部维护了一个单链表。单链表的before和after使其具有了有序的特性。TreeMap:内部通过Comprator比较器实现了排序。

总结

我上面的论述也是参考的网上我认为不错的针对HashMap的讲解,然后加入了我自己的理解,让大家能够更好的理解其中的原理内容,如果你有其他问题,欢迎关注我的公众号:Java时间屋 进行讨论。

 

责任编辑:武晓燕 来源: Java时间屋
相关推荐

2023-09-12 11:00:38

HashMap哈希冲突

2022-03-28 12:00:57

HashMap容量hash

2024-09-04 15:17:23

2024-05-24 10:15:36

2022-08-29 07:31:48

HashMap线程扩容

2022-01-20 08:44:25

HashMap死循环开放性

2020-04-28 09:15:58

HashMapJava数组

2022-01-18 06:59:50

HashMap循环底层

2020-09-29 15:24:07

面试数据结构Hashmap

2015-09-07 09:15:54

Java面试题HashMap

2020-12-03 07:39:50

HashMap底层数据

2020-06-19 15:32:56

HashMap面试代码

2021-12-08 06:53:28

HashMap面试JDK 8

2022-05-27 08:18:00

HashMapHash哈希表

2023-02-17 14:35:15

HashMapNode类型

2022-09-13 14:44:40

HashMap哈希表红黑树

2020-10-21 07:50:52

HashMapJava数组

2020-05-13 14:35:47

HashMap面试官Java

2024-11-05 09:28:52

2023-07-26 07:15:13

HashMapArrayListLinkedList
点赞
收藏

51CTO技术栈公众号