面试题分享之Java集合篇(三)

注意:文章若有错误的地方,欢迎评论区里面指正 🍭 

系列文章目录

  • 面试题分享之Java基础篇(二)
  • 面试题分享之Java基础篇(三)
  • 面试题分享之Java集合篇(一)、

  • 面试题分享之Java集合篇(二)


前言

哈喽,小伙伴们,昨天我们见识了HaspMap常见的面试题,如:HaspMap的get、put、resize方法的原理等等,废话不多说,今天继续来给大家分享几道Java集合的高频面试题。🌈


一、HashMap怎么计算 key 的 hash 值的?

先贴上源码(jdk1.8为例):

    /**
    这是官方注释

     计算 key.hashCode() 并将 (XOR) 更高的哈希位传播到更低的哈希位。
    由于该表使用二次幂掩码,因此仅比当前掩码高位变化的哈希集将始终发生冲突。
    (在已知的例子中,有一组浮点键在小表中保存连续的整数。
    因此,我们应用了一个变换,将更高位的影响向下传播。
    在速度、实用性和比特扩展质量之间需要权衡。
    由于许多常见的哈希集已经合理分布(因此不会从扩展中受益),
    并且由于我们使用树来处理 bin 中的大量冲突,
    因此我们只是以最便宜的方式对一些移位进行异或运算,
    以减少系统损失,并合并最高位的影响,
    否则由于表边界,这些比特永远不会用于索引计算。
     */
    static final int hash(Object key) {
        int h;
        /*
        如果key是null,则直接返回0作为哈希值
        如果不为null,返回原hashCode值和原hashCode值
        无符号右移16位的值按位异或的结果
        按位异或:将两个十进制数先转化为二进制数,相同的就取0,不同的就取1
        例如:15 跟 16 按位异或
        16    1 0 0 0 0  8421
        15  ^ 0 1 1 1 1
            ------------
              1 1 1 1 1  ---> 31
                
        */
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

🧑‍💼面试官追问:右移16位有什么好处?

  1. 右移16位,正好是32位的一半,高半区和低半区做异或操作,就是为了混合原始哈希码的高位与地位,以此来加大低位的随机性。
  2. 设计者考虑到现在hashCode分布的已经不错了,而且当发生较大碰撞时也用树形存储降低了冲突,仅仅异或一下,少了系统的开销,也不会造成因为高位没有参与下标的计算,从而引起碰撞。

二、HashMap如何解决hash冲突

不清楚什么是hash冲突小伙伴可以参考:

面试题分享之Java基础篇(二)-CSDN博客

1、链地址法(也称为拉链法)

  • 当两个或多个键的哈希值相同时,它们不会被存储在同一个桶(bucket)中,而是会被链接到同一个桶内的链表中。
  • HashMap在内部使用Node<K,V>[]数组来存储桶,每个桶可以是一个链表或红黑树(在Java 8及更高版本中,当链表长度超过某个阈值时,会转换为红黑树以提高性能)。
  • 当发生哈希冲突时,新的键值对将被添加到相应桶的链表或红黑树的末尾。

2、开放地址法

  • 这种方法并不是HashMap直接使用的,但在其他哈希表实现中可能会看到。
  • 当发生哈希冲突时,会按照一定的规则(如线性探测、平方探测等)在哈希表中寻找下一个空闲位置来存储键值对。

3、再哈希法

  • 这不是HashMap的标准做法,但在某些哈希表实现中可能会使用。
  • 当通过第一个哈希函数计算得到的哈希值发生冲突时,使用第二个哈希函数再次计算哈希值,并尝试将键值对存储在新的位置。如果仍然冲突,可以继续使用更多的哈希函数。

​4、建立公共溢出区

  • 这种方法也不是HashMap的标准做法。
  • 当哈希表的主区域无法容纳更多的键值对时,可以将它们存储在一个单独的溢出区域中。然而,在HashMap中,当容量不足时,它会通过重新分配更大的数组并进行重新哈希来扩展其容量。

对于HashMap来说,它主要依赖链地址法(拉链法)来解决哈希冲突。当向HashMap中插入新的键值对时,它会首先计算键的哈希值,并使用该哈希值来确定应该将其存储在哪个桶中。如果该桶已经存在其他键值对(即发生了哈希冲突),则将新的键值对添加到该桶的链表或红黑树的末尾。

此外,为了优化性能并减少哈希冲突的可能性,HashMap还使用了以下技术:

  • 哈希函数HashMap使用了一个精心设计的哈希函数来计算键的哈希值。这个函数试图将键均匀地分布到不同的桶中,以减少哈希冲突的可能性。
  • 动态扩容:当HashMap中的键值对数量超过其容量的一定比例(称为加载因子,默认为0.75)时,它会自动扩容其内部数组的大小,并重新哈希所有键值对以确保它们仍然被正确地分配到新的桶中。这有助于减少哈希冲突并提高性能。

三、HashMap多线程操作导致死循环问题知道吗?

        这个问题主要源于 HashMap 的扩容机制和链表或红黑树的节点转移过程。在扩容时,HashMap 会创建一个新的数组,并重新计算每个键的哈希值以确定它们在新数组中的位置。这个过程需要遍历原数组中的所有桶(bucket),并将桶中的链表或红黑树节点转移到新数组对应的桶中。

        如果在这个过程中发生并发修改(例如,另一个线程插入或删除了键值对),就可能导致节点在新旧数组之间形成循环引用,进而引发死循环。具体来说,如果两个线程同时对一个桶进行扩容操作,并且其中一个线程在遍历链表或红黑树的过程中修改了链表或红黑树的结构(例如,删除了某个节点),那么另一个线程在继续遍历时就可能会遇到已经遍历过的节点,从而形成循环引用。

四、说说HashMap 和 HashSet 区别?

HashSet 底层就是基于 HashMap 实现的。两者主要区别

HashSetHshMap
数据结构和存储方式实现Set接口,HashSet内部使用哈希表来存储元素,并通过元素的哈希码来判断是否重复实现Map接口,HashMap存储的是键值对,键(key)是唯一的,值(value)可以重复
元素类型和唯一性存储的是单一的元素类型(如整数、字符串等),并且元素必须是唯一的,不会存在重复的元素存储的是键值对,键和值可以是不同类型的对象。键必须是唯一的,而值可以重复
查找速度速度相对较慢速度相对较快

五、ConcurrentHashMap在Jdk1.7和Jdk1.8的实现原理

1、ConcurrentHashMap跟HashMap的区别

  • HashMap的底层数据结构主要是数组+链表(确切的说是由链表为元素的数组),ConcurrentHashMap的底层数据结构在JDK 1.7中是基于Segment数组+HashEntry数组+链表,而在JDK 1.8中则改为了Node+红黑树。
  • HashMap是非线程安全的,它不能在多线程环境下正确工作。当多个线程同时对HashMap进行修改时,可能会导致数据不一致或者抛出异常。而ConcurrentHashMap是线程安全的,它使用了锁分段技术(lock striping)来实现并发安全性,允许多个线程在不同的段上并发地进行修改操作。

2、在JDK1.7实现原理 

JDK1.7ConcurrentHashMap采用数组+Segment+分段锁的方式实现。

什么是Segment呢?

        ConcurrentHashMap中的分段锁称为Segment.它类似HashMap的结构,内部拥有一个Entry数组,数组中的每个元素又是一个链表,同时又是一个ReentrantLock(Segment继承了ReentrantLock)

Concurrent使用分段锁机制,将数据一段一段的存储,然后给每一段数据加锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据可以被其他线程访问,能够实现真正的并发访问。

Concurrent的扩容机制:当某个 Segment 中的元素数量超过其容量阈值时,会触发扩容操作。扩容操作会创建一个新的 Segment 数组,并将原有的 Segment 中的元素重新分配到新的 Segment 中。这个过程中会涉及到大量的数据迁移和重哈希操作,因此是一个耗时的过程。但由于采用了分段锁机制,扩容操作可以并行进行,从而提高了性能。

ConcurrentHashMap定位一个元素需要经过两次hash过程:第一次定位到Segmnent,第二次定位到元素所在的链表的头部。

该结构的优缺点:

缺点:Hash的过程要比普通的HashMap要长
优点:写操作时只对元素所在的Segment进行加锁即可,不会影响到其他Segment,在最理想的情况下,ConcurrentHashMap可以最高同时支持Segment数量大小的写操作(写操作非常平均的分布在所有Segment上)。所以,通过这种结构,ConcurrentHashMap并发能力大大提高。

3、在JDK1.8实现原理

在 JDK 1.8 中,ConcurrentHashMap 的实现发生了较大的变化,主要采用了CAS(Compare-And-Swap)操作、Synchronized关键字以及Node+红黑树的存储结构。

  1. CAS 操作:CAS 是一种无锁算法,它通过比较并交换操作来实现对共享变量的原子操作。在 ConcurrentHashMap 中,CAS 操作被用于实现节点的插入、更新和删除等操作。由于 CAS 操作具有原子性,因此可以保证多线程环境下的数据一致性。
  2. Synchronized:虽然 JDK 1.8 中的 ConcurrentHashMap 摒弃了分段锁机制,但它仍然使用了 Synchronized 关键字来保证对共享变量的同步访问。具体来说,ConcurrentHashMap 的每个节点(Node)在更新数据时都会使用 Synchronized 来保证操作的原子性。
  3. Node+红黑树:在 JDK 1.8 中,ConcurrentHashMap 的内部存储结构由 Segment+HashEntry 改为了 Node+红黑树。具体来说,当某个桶(bucket)中的链表长度超过一定的阈值(默认为 8)时,会将该链表转换为红黑树,以提高查询效率。红黑树是一种自平衡的二叉搜索树,它的查询、插入和删除操作的时间复杂度都是 O(logN)。

总结

这两期的面试题都偏理论性的,要求小伙伴有很好的数据结构的基础,深入源码分析,多理解不要死记硬背。好了,今天的分享就到这里,拜拜。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/592166.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营第25天 | 216.组合总和III、17.电话号码的字母组合

代码随想录算法训练营第25天 | 216.组合总和III、17.电话号码的字母组合 自己看到题目的第一想法看完代码随想录之后的想法 链接: 216.组合总和III 链接: 17.电话号码的字母组合 自己看到题目的第一想法 216.组合总和III&#xff1a;递归函数终止条件为搜索得到的数相加为n&…

【架构系列】RabbitMQ应用场景及在实际项目中如何搭建可靠的RabbitMQ架构体系

作者:后端小肥肠 创作不易&#xff0c;未经允许禁止转载。 1. 前言 RabbitMQ&#xff0c;作为一款高性能、可靠的消息队列软件&#xff0c;已经成为许多企业和开发团队的首选之一。它的灵活性和可扩展性使得它适用于各种应用场景&#xff0c;从简单的任务队列到复杂的分布式系统…

阿里低代码引擎学习记录

官网 一、关于设计器 1、从设计器入手进行低代码开发 设计器就是我们用拖拉拽的方法&#xff0c;配合少量代码进行页面或者应用开发的在线工具。 阿里官方提供了以下八个不同类型的设计器Demo&#xff1a; 综合场景Demo&#xff08;各项能力相对完整&#xff0c;使用Fusion…

【前端项目——分页器】手写分页器实现(JS / React)

组件介绍 用了两种方式实现&#xff0c;注释详细~ 可能代码写的不够简洁&#xff0c;见谅&#x1f641; 1. 包含内容显示的分页器 网上看了很多实现&#xff0c;很多只有分页器部分&#xff0c;没和内容显示联动。 因此我增加了模拟content的显示&#xff0c;这里模拟了32条数…

Python数据分析案例44——基于模态分解和深度学习的电负荷量预测(VMD+BiGRU+注意力)

案例背景 承接之前的案例&#xff0c;说要做模态分解加神经网络的模型的&#xff0c;前面纯神经网络的缝合模型参考数据分析案例41和数据分析案例42。 虽然我自己基于各种循环神经网络做时间序列的预测已经做烂了.....但是还是会有很多刚读研究生或者是别的领域过来的小白来问…

Monorepo(单体仓库)与MultiRepo(多仓库): Monorepo 单体仓库开发策略与实践指南

&#x1f31f; 引言 在软件开发的浩瀚宇宙里&#xff0c;选择合适的代码管理方式是构建高效开发环境的关键一步。今天&#xff0c;我们将深入探讨两大策略——Monorepo&#xff08;单体仓库&#xff09;与MultiRepo&#xff08;多仓库&#xff09;&#xff0c;并通过使用现代化…

Vue3 + Vite + TypeScript + Element-Plus创建管理系统项目

官方文档 Vue3官网 Vite官方中文文档 创建项目 使用npm命令创建项目&#xff1a; npm create vitelatest输入项目名称&#xff1a; ? Project name:项目名选择vue&#xff1a; ? Select a framework: - Use arrow-keys. Return to submit.Vanilla > VueReactPrea…

【网站项目】木里风景文化管理平台

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

CSS精灵图、字体图标、HTML5新增属性、界面样式和网站 favicon 图标

精灵图 为什么要使用精灵图 一个网页中往往会应用很多小的背景图像作为修饰&#xff0c;当网页中的图像过多时&#xff0c;服务器就会频繁地接收和发送请求图片&#xff0c;造成服务器请求压力过大&#xff0c;这将大大降低页面的加载速度,因此&#xff0c;为了有效地减少服务…

JAVA基础|常用API-JDK8之前传统的日期,时间

一. Date &#xff08;一&#xff09;说明 代表的是日期和时间 &#xff08;二&#xff09;常用的用法 构造器说明public Date()创建一个Date对象&#xff0c;代表的是系统当前此刻日期时间public Date(long time)把时间毫秒值转换成Date日期对象 常见方法说明public long …

算法提高之潜水员

算法提高之潜水员 核心思想&#xff1a;二维01背包 两个容量v1v2注意状态计算时j和p可以<各自的v #include <iostream>#include <cstring>#include <algorithm>using namespace std;const int N 1010,M 80,K 22;int f[K][M];int k,V1,V2;int main(){ci…

FloodFill-----洪水灌溉算法(DFS例题详解)

目录 一.图像渲染&#xff1a; 代码详解&#xff1a; 二.岛屿数量&#xff1a; 代码详解&#xff1a; 三.岛屿的最大面积&#xff1a; 代码详解&#xff1a; 四.被围绕的区域&#xff1a; 代码详解&#xff1a; 五.太平洋大西洋水流问题&#xff1a; 代码详解&#x…

锂电池充放电方式曲线

作为一种“化学能-电能”相互转换的能量装置&#xff0c;锂电池在使用过程中必然会进行充电和放电&#xff0c;合理的充放电方式既能减轻锂电池的损伤程度&#xff0c;又能充分发挥锂电池的性能&#xff0c;具有重要的应用价值。 如《GB/T 31484-2015&#xff1a;电动汽车用动…

非对称齿轮的跨棒距算的对不对

前面有一期咱们聊了非对称齿轮《》&#xff0c;非对称齿轮的齿厚测量一般都为跨棒距。最近研究了下计算方法&#xff0c;对计算结果的正确性做了下验证。 在MATLAB中编制了相关的计算程序&#xff1a; 齿轮的模数4&#xff0c;左侧分度圆压力角25&#xff0c;右侧分度圆压力角…

Sqli-labs第一关到第四关

目录 一&#xff0c;了解PHP源代码 二&#xff0c;破解第一关 2.1在了解完源码之后&#xff0c;我们重点看一下 2.2破解这道题表中有几列 2.3查看表中哪一列有回显 2.4查询库&#xff0c;表&#xff0c;列信息 三&#xff0c;总结 前提&#xff1a; 之所以把1234关…

MySQL基础_1.MySQL概述

文章目录 一、关系型数据库和非关系型数据库1.1 关系型&#xff08;RDBMS&#xff09;1.2 非关系型&#xff08;非RDBMS&#xff09; 二、常用的基础语句2.1 查看表的创建信息2.2 编码问题 一、关系型数据库和非关系型数据库 1.1 关系型&#xff08;RDBMS&#xff09; 是最古…

都上3D数字孪生了,2D的WEB组态和大屏可视化未来的发展在哪里?趋势是基于页面嵌套、蓝图连线等新技术,与功能业务应用融合

首先回顾下组态工具的发展史&#xff1a; 回顾发展史&#xff0c;WEB组态终于可以搭建业务系统了&#xff01;&#xff08;页面嵌套 节点编辑 WEB组态 上位机 大屏可视化 无代码 0代码 iframe nodered 蓝图&#xff09;-CSDN博客文章浏览阅读624次&#xff0c;点赞12次&#x…

ThreeJS:纹理的颜色空间

色彩空间Color Space 在ThreeJS中&#xff0c;纹理的colorSpace属性用于定义文里的颜色空间。 颜色空间是一个用于描述颜色的数学模型&#xff0c;在现实生活中&#xff0c;人眼可以观察到无数种颜色&#xff0c;而颜色空间就是用来描述这些颜色的一个方法&#xff0c;不同的颜…

C语言-自定义类型:结构体,枚举,联合

目录 一、结构体1.1 结构体变量的定义和初始化1.2 结构体内存对齐1.3 修改默认对齐数1.4 结构体传参 二、位段2.1 什么是位段2.2 位段的内存分配2.3 位段的跨平台问题2.4 位段的应用 三、枚举3.1 枚举类型的定义3.2 枚举的优点 四、联合&#xff08;共用体&#xff09;4.1 联合…

c#数据库: 9.删除和添加新字段/数据更新

先把原来数据表的sexy字段删除,然后重新在添加字段sexy,如果添加成功,sexy列的随机内容会更新.原数据表如下: using System; using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Data.SqlClient; using System.Linq; using System.…
最新文章