面试题分享之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 842115 ^ 0 1 1 1 1------------1 1 1 1 1 ---> 31*/return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
- 右移16位,正好是32位的一半,高半区和低半区做异或操作,就是为了混合原始哈希码的高位与地位,以此来加大低位的随机性。
- 设计者考虑到现在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
实现的。两者主要区别:
HashSet | HshMap | |
数据结构和存储方式 | 实现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.7中ConcurrentHashMap采用数组+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+红黑树的存储结构。
- CAS 操作:CAS 是一种无锁算法,它通过比较并交换操作来实现对共享变量的原子操作。在
ConcurrentHashMap
中,CAS 操作被用于实现节点的插入、更新和删除等操作。由于 CAS 操作具有原子性,因此可以保证多线程环境下的数据一致性。- Synchronized:虽然 JDK 1.8 中的
ConcurrentHashMap
摒弃了分段锁机制,但它仍然使用了Synchronized
关键字来保证对共享变量的同步访问。具体来说,ConcurrentHashMap
的每个节点(Node)在更新数据时都会使用Synchronized
来保证操作的原子性。- Node+红黑树:在 JDK 1.8 中,
ConcurrentHashMap
的内部存储结构由Segment+HashEntry
改为了Node+红黑树
。具体来说,当某个桶(bucket)中的链表长度超过一定的阈值(默认为 8)时,会将该链表转换为红黑树,以提高查询效率。红黑树是一种自平衡的二叉搜索树,它的查询、插入和删除操作的时间复杂度都是 O(logN)。
总结
这两期的面试题都偏理论性的,要求小伙伴有很好的数据结构的基础,深入源码分析,多理解不要死记硬背。好了,今天的分享就到这里,拜拜。
相关文章:
面试题分享之Java集合篇(三)
注意:文章若有错误的地方,欢迎评论区里面指正 🍭 系列文章目录 面试题分享之Java基础篇(二)面试题分享之Java基础篇(三) 面试题分享之Java集合篇(一)、 面试题分享之Ja…...
【python】模拟巴特沃斯滤波器
巴特沃斯滤波器(Butterworth Filter),以其设计者斯蒂芬巴特沃斯(Stephen Butterworth)的名字命名,是一种具有平滑频率响应的滤波器。这种滤波器在频域中具有非常平坦的无波纹响应,直到它达到截止…...
面试题:简述Go的垃圾回收机制
Go的GC(Garbage Collection, 垃圾回收)机制主要是用来自动释放不再被程序使用的内存,以防止内存泄漏。Go的垃圾回收是并发的,也就是说,它在主程序运行的同时进行垃圾回收。 1. 标记清除(Mark and Sweep) Go的垃圾回收器主要使用的是标记清除…...
Vue、React实现excel导出功能(三种实现方式保姆级讲解)
第一种:后端返回文件流,前端转换并导出(常用,通常公司都是用这种方式) 第二种:纯后端导出(需要了解) 第三种:纯前端导出(不建议使用,数据处理放…...
初识C语言——第十六天
C语言中的语句结构类型:顺序/选择/循环 分支语句 if else switch 循环语句 while for do whlie goto语句 代码练习:找两个整数的最大公约数和最小公倍数 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h>//int main() //{ // int age 60; // if (ag…...
Vue的省份联动
Vue的省份联动 一、安装依赖库 npm install element-china-area-data -Snpm install element-ui --save全局使用elemntui组件库 import ElementUI from element-ui; import element-ui/lib/theme-chalk/index.css;Vue.use(ElementUI);二 、代码如下 <template><div…...
element-ui skeleton 组件源码分享
今日简单分享 skeleton 骨架屏组件源码,主要从以下四个方面来讲解: 1、skeleton 组件的页面结构 2、skeleton 组件的属性 3、skeleton item 组件的属性 4、skeleton 组件的 slot 一、skeleton 组件的页面结构 二、skeleton 组件的属性 2.1 animate…...
深度学习:基于TensorFlow、Keras,使用长短期记忆神经网络模型(LSTM)对Microsoft股票进行预测分析
前言 系列专栏:机器学习:高级应用与实践【项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目,每个项目都处理一组不同的问题,包括监督和无监督学习、分类、回归和聚类,而且涉及创建深度学…...
【websocket-客户端可视化工具】
postman 新版postman (版本v11以上) ,除了http协议,还支持了Websocket,MQTT,gRPC等多种连接协议,可以作为多种协议的客户端,使用起来非常方便。 使用 服务端代码 这里以websocket协议举例,代…...
STC8增强型单片机开发——C51版本Keil环境搭建
一、目标 了解C51版本Keil开发环境的概念和用途掌握C51版本Keil环境的安装和配置方法熟悉C51版本Keil开发环境的使用 二、准备工作 Windows 操作系统Keil C51 安装包(可以从Keil官网下载)一款8051单片机开发板 三、搭建流程 环境搭建的基本流程…...
Ansible——playbook编写
目录 环境配置 一、简介 1.什么是playbook 2.playbook组成 二、应用实例 1.基础命令 1.编写 ceshi1.yaml 文件 2.运行Playbook 2.定义、引用变量 1.编写ceshi2.yaml文件 3.指定远程主机sudo切换用户 1.编写ceshi3.yaml文件 2.修改被控主机sudoers文件 3.给zhangsa…...
95、动态规划-编辑距离
递归暴力解法 递归方法的基本思想是考虑最后一个字符的操作,然后根据这些操作递归处理子问题。 递归函数定义:定义一个递归函数 minDistance(i, j),表示将 word1 的前 i 个字符转换成 word2 的前 j 个字符所需的最小操作数。 递归终止条件…...
linux调试
文章目录 1. 使用打印来调试1.1 重定向1.2 标准预定义宏1.3 日志代码 2. 内核异常2.1 内核打印2.1.1 打印级别2.1.2 跟踪异常2.1.3 动态打印2.1.4 RAM console 2.2 OOPS2.2.1 有源代码的情况2.2.2 没有源代码的情况 3 查看日志4 工具调试 1. 使用打印来调试 1.1 重定向 2>…...
【C++】string类的使用②(容量接口Capacity || 元素获取Element access)
🔥个人主页: Forcible Bug Maker 🔥专栏: STL || C 目录 前言🔥容量接口(Capacity)size和lengthcapacitymax_sizereserveresizeclearemptyshrink_to_fit 🔥元素获取(Ele…...
【漏洞复现】某小日子太阳能系统DataCube3审计
漏洞描述 某小日子太阳能系统DataCube3终端测量系统 多个漏洞利用方式 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和利益,未经授权请勿利用文章中的技术资料对任何计算机系统进…...
探索Java的未来
目录 一、云计算与大数据 二、人工智能与机器学习 三、物联网与边缘计算 四、安全性与性能优化 五、社区与生态 Java,作为一种广泛使用的编程语言,自其诞生以来就以其跨平台性、面向对象特性和丰富的库资源赢得了开发者的青睐。然而,随着…...
Web3 ETF软件开发
开发Web3 ETF软件涉及到金融、法律和技术等多个领域的专业知识,因此存在以下技术难点,开发Web3 ETF软件是一项复杂的技术挑战,需要综合考虑各种因素。开发人员需要具备较强的技术能力和跨学科知识才能成功开发Web3 ETF软件。北京木奇移动技术…...
初始MySQL
初始化MySQL数据库通常涉及以下步骤: 下载并安装MySQL: 你可以从MySQL官方网站下载适合你的操作系统的MySQL安装包。安装时,遵循安装向导的步骤,通常包括选择安装位置、选择组件(例如MySQL服务器、MySQL Workbench等&a…...
STM32项目下载清单(不定时更新)
收集的一些资料,分享下载 电赛一等奖作品,老人健康监测智能手表(STM32F4主控) STM32数字示波器源码数字信号处理教程、配套实例基于stm32 nucleo_L476的智能灯(操作说明源码)基于STM32 NUCLEO板设计彩色LE…...
thinkphp5 配合阿里直播实现直播功能流程
要为你提供一个更详细的教程来结合ThinkPHP 5和阿里直播SDK实现直播功能,需要涵盖的内容相对较多。不过,我可以为你提供一个大致的、更详细的步骤指南,供你参考和扩展: 1. 准备工作 a. 注册阿里云账号 前往阿里云官网注册账号&…...
安卓手机APP开发__媒体3格式转换器__常见问题解答
安卓手机APP开发__媒体3格式转换器__常见问题解答 目录 1 为什么在示例的APP中我不能读取到本地的文件? 2 在一个特定的设备为什么导出失败? 3 媒体3格式转换器支持转码(或者是录制)远程的媒体吗? 4 媒体3格式转换…...
leetcode-有重复数字的全排列-98
题目要求 思路 1.同【没有重复项的全排列-97】这个题一样,都是递归的题,区别在于这个可能会包含重复的数字,因此,不能只是简单的通过两个值是否相等然后用标志位标记,而是新增了一个数组,这个数组专门用于…...
Unity数据持久化之XML
目录 数据持久化XML概述XML文件格式XML基本语法XML属性 C#读取存储XMLXML文件存放位置C#读取XML文件C#存储XML文件 实践小项目必备知识点XML序列化(不支持字典)XML反序列化IXmlSerializable接口让Dictionary支持序列化反序列化 数据持久化XML概述 什么是…...
Leetcode 226:翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 思路:使用递归 //使用前序遍历翻转树public static TreeNode invertTree(TreeNode root){if(rootnull) return root;swap(root);invertTree(root.left);invertTree(root.rig…...
柯里化与无参装饰器
柯里化 柯里化的概念:柯里化(Currying)在Python中是一种编程技术,它将原本接受多个参数的函数转换为一系列接受单个参数的函数。这种方法以逻辑学家Haskell Curry的名字命名。 简而言之就是将一次函数调用变成先放入一个参数得到…...
Spring事务失效的场景
1. 事务方法执行期间出现了异常,但是并未指定rollbackFor: Spring默认只会在遇到error和RunTimeException时才会回滚。 public boolean rollbackon ( Throwable ex){return (ex instanceof RuntimeException || ex instanceof Error); } 2. 事务方法执行期间出现了…...
Python基础学习之datetime模块
在Python编程中,处理日期和时间是一个常见的需求。Python的datetime模块提供了丰富的类和方法,用于表示和操作日期、时间、时间间隔等。本文将详细介绍Python的datetime模块,并给出一些实用的示例。 1. datetime模块概览 datetime模块是Pyt…...
在AI大模型中全精度和半精度参数是什么意思?
环境: 大模型中 问题描述: 在AI大模型中全精度和半精度参数是什么意思? 解决方案: 在深度学习和高性能计算领域,"全精度"和"半精度"通常指的是模型中使用的数值表示的精度,具体涉…...
刷题记录2
文章目录 刷题记录21047.删除字符串中的所有相邻重复项150.逆波兰表达式求值239.滑动窗口最大值347.前k个高频元素144.二叉树前序遍历(145、94后序、中序)102.二叉树的层序遍历226.翻转二叉树101.对称二叉树104.二叉树的最大深度111.二叉树的最小深度222.完全二叉树的节点个数 …...
【配置】Docker搭建JSON在线解析网站
一个python朋友需要,顺便做一下笔记 正常用菜鸟的就够了,点下面 JSON在线解析 云服务器打开端口8787 连接上docker运行 docker run -id --name jsonhero -p 8787:8787 -e SESSION_SECRETabc123 henryclw/jsonhero-webhttp://ip:8787访问 Github&…...
中国空间站/电商seo是什么意思
macOS的最新版本Big Sur具有许多新功能和改进,我们大多数人都希望尽快安装它。在大多数情况下,一切都会正常进行,因此我们可以快速启动并运行。但是,有时它运行不正常,并且您会看到一条消息,指出无法完成ma…...
彬州市人民政府门户网站/yahoo搜索引擎入口
1.先安装IIS啊,就是都勾选上就可以了 在控制面板->程序->程序和功能,点击左边的“打开或关闭WIndows功能”,在弹出的窗口中就可以看到IIS啦; 2.ArcServer 当中竟然有一步需要Restart IIS服务!重启了之后他还有这…...
vue做单页面网站/网络平台推广
前几天的3.15晚会上曝光了利用智能机器人,一天打4万个骚扰电话,从而赚取利润的黑色产业链。 阿里的工程师恼了,技术是用来让人们生活变美好的,不是被利用来走向阴暗的。 机器人的问题交给机器人! 工程师们用业余时间开…...
网站建设 提案 框架/百度店铺注册
在线QQ客服:1922638专业的SQL Server、MySQL数据库同步软件当我们不确定数据结构字段或混乱时,很难根据一个概念提取数据。什么数据库适合使用?答案是什么?如果使用传统数据库,则必须保留额外的字段,其中10…...
网络设计培训学校长沙/深圳网站设计专业乐云seo
今天我们就不多余介绍前面的安装步骤了,具体可以参考上一篇6.8的创建,主要讲一下另一部分. 首先我们能看到如图的界面,直接进入之后点击enter键. 我建议大家选择英文,因为在我们后面的学习中我们的日志文件,错误代码都会以英文的方式呈现,有的时候的中文直译会不太准确,我们也要…...