Map面试题

这篇博客深入探讨了HashMap的底层数据结构、工作原理、哈希函数设计、扩容机制、并发安全等核心知识点。从JDK8的变化到红黑树的引入,详细阐述了HashMap及其相关类如HashTable、ConcurrentHashMap的区别和优化策略。
摘要由CSDN通过智能技术生成

一、HashMap底层数据结构

JDK7之前,HashMap 底层是 hash 数组和单向链表实现。

 JDK8后采用数组+链表+红黑树的数据结构。

 二、HashMap 的工作原理

          在创建HashMap对象时,可以初始化默认容量和负载因子,当然也可以在创建HashMap对象时指定初始容量和负载因子(这取决于创建HashMap对象时调用的构造函数)。
        通过put()方法存储数据,当使用put()方法将键和值传递给HashMap时,首先会使用key的hashCode()方法获取key的hash值,然后通过公式:hash值 =(通过hashCode()得到的哈希值)^(异或)(哈希值右移16位),得到int类型的hash值,此hash值可以在存储时计算数据在hash桶数组中的下标位置,hash桶是node类型的数组,存储的都是node对象,而node本质上是Map.Entry(主要方便转化为红黑树),key和value都是先存储到node中,然后把node在存储到hash桶数组中,而node存储在hash桶数组中的下标位置是通过key的hash值计算出来的。
        通过get(key)方法获取存储在HashMap中的数据,首先会通过key的hashCode()方法获取到key的hash值,首先会使用key的hashCode()方法获取key的hash值,然后通过公式:hash值 =(通过hashCode()得到的哈希值) ^(异或)(哈希值右移16位),得到int类型的hash值,此hash值可以在获取数据时,计算出数据在hash桶数组中的下标位置。之后调用HashMap的getNode()方法,在此方法中会判断当前的hash桶数组是否存有数据(判断是否null,判断长度是否为0,通过计算下标位置获取数据是否为null),如果没存有数据,则返回null,如果存有数据,则需要判断之前取得的int类的hash值和获取数据的hash值以及传递过来的key和获取数据的key地址及内容是否一致,一致,返回获取的数据,然后再获取value的值,返回给调用方;不一致, 则判断获取的数据是否是红黑树,如果是红黑树则从根节点开始进行匹配如果有对应的数据则返回,然后再获取value的值,返回给调用方,否则返回Null;如果是链表的话就会循环查询链表,如果当前的节点不匹配的话就会从当前节点获取下一个节点来进行循环匹配,如果有对应的数据则返回,然后再获取value的值,返回给调用方,否则返回Null。

三、使用HashMap时,当两个对象的 hashCode 相同怎么办?

        因为HashCode 相同,equals()方法操作可能相等,也可能不相等,所hashCode值相同并不能说明是同一个对象,只有两个对象所在数组的下标相同,"碰撞"才会发生。如果振的hash值冲突了, HashMap会把产生hash冲突的hash值以链表形式存储在index位置上。

四、HashMap 的哈希函数怎么设计的?

HashMap的hash()函数源码如下:

 hash 函数是先拿到通过 key 的 hashCode ,是 32 位的 int 值,然后让hashCode 的高 16 位和低 16 位进行异或操作。两个好处:一定要尽可能降低 hash 碰撞,越分散越好; 算法一定要尽可能高效,因为这是高频操作, 因此采用位运算;

五、HashMap遍历方法有几种?

Iterator 迭代器
1 public class MapDemo1 {
2
3 public static void main ( String [] args ) {
4 HashMap < String , String > map = new HashMap <> ();
5 map . put ( "name1" , " 张三 " );
6 map . put ( "name1" , " 张三 " );
7 map . put ( "name2" , " 李四 " );
8 map . put ( "name3" , " 王五 " );
9 map . put ( "name4" , " 赵六 " );
10
11 Iterator < Map . Entry < String , String >> iterator =
map . entrySet (). iterator ();
12 while ( iterator . hasNext ()){
13 Map . Entry < String , String > entry = iterator . next ();
14 String key = entry . getKey ();
15 String value = entry . getValue ();
16 //String value1 = map.get(key);
17 System . out . println ( key + "‐‐‐‐‐" + value );
18 }
19 }
20 }
最常见的使用方式,可同时得到 key、value 值
1 public class MapDemo1 {
2
3 public static void main ( String [] args ) {
4 HashMap < String , String > map = new HashMap <> ();
5 map . put ( "name1" , " 张三 " );
6 map . put ( "name1" , " 张三 " );
7 map . put ( "name2" , " 李四 " );
8 map . put ( "name3" , " 王五 " );
9 map . put ( "name4" , " 赵六 " );
10
11 // 获取所有的 key
12 Set < String > keySet = map . keySet (); 13 Iterator < String > iterator = keySet . iterator ();
14 while ( iterator . hasNext ()){
15 String next = iterator . next ();
16 System . out . println ( next );
17 }
18 // 获取所有的 value
19 Collection < String > values = map . values ();
20 for ( String value : values ) {
21 System . out . println ( value );
22 }
23
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值