java异或_JAVA面试必备之HashMap必会点

229f706fcb381cfa8bce23da3e731e97.png

08996bb4953bf096129cb1a196231771.png

今天我们就面试会问到关于HashMap的问题进行一个汇总,以及对这些问题进行解答。

1、HashMap的数据结构是什么?

2、为啥是线程不安全的?

3、Hash算法是怎样实现的?

4、HashMap是如何处理Hash碰撞的?

5、增加元素的方法是怎么实现的?

6、获取元素的方法时怎么实现的?

以上这些问题在面试中出现的频率往往比较高,在对HashMap不太了解的情况下,往往很难将这些问题答全,笔者就带领对这块不熟悉的小伙伴们一起,一步一步解析以上的问题。

1、HashMap的数据结构是什么?

对于这个问题,笔者建议回答的时候对JAVA版本进行区分,因为不同版本下,HashMap的结构是有些差异的。

回答:在JDK1.8之前HashMap是数组+链表的形式,JDK1.8包括之后是数组+链表+红黑树。本文讲的HashMap是基于JDK1.8。

2、为啥是线程不安全的?

多个线程某个时刻同时操作HashMap并执行put操作,且Hash值相同,这个时候需要解决冲突。很多方法如put() 、addEntry() 、resize() 等都不是同步的。

3、Hash算法是如何实现的?

0c32467ae1a2a871f7d1798f462f7055.png

"^"为异或符号其计算机符号为xor,相同为0,相异为1,如0^0=0 、0^1=1.">>>"为右移动符号,左侧补零。图中h>>>16就是将h的高16位换到h的低16位,而之前的高16位全补零。

9cee2ecfef8b821fe2f601fa6136d4c1.png

这里有童鞋可能就会问了,为什么要进行这个向右移16位且异或的操作?

359404d559f8cbfd11a9aaca748b765b.png

4、HashMap是如何处理Hash碰撞的?

HashMap采用的是链表法,将hash值相同的元素放在一个链表下。

5、增加元素的方法是怎么实现的?

2e084b15bccc98b3a25311769c723609.png
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;// 如果说桶(也就是数组,以下都用"桶"代替)为空,或者桶大小为0 则进行初始化// 这里要区桶大小 和 桶内元素的大小 桶大小是指桶装东西的能力// 桶内元素大小 是指桶装了多少东西 if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 这里是帮助元素查找元素在桶中的定位 如果定位的位置没有元素 那么// 直接将元素放入桶的该位置就行    if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {// 运行到这说明定位的位置已经有元素了Node<K,V> e; K k;// 既然有人霸占元素的位置,那么就要与该元素进行对比,看看自己的Hash值和// key值是不是和该位置的元素一直,如果都一直就记录下该元素以下为e// 说明有一个和我插入元素的key一样的元素 后续可能要用新值替换旧值if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;// 如果只是Hash值相等而key不等,这里就是Hash碰撞啦,要解决hash碰撞// hashMap采用的是链地址法 就是碰撞的元素连成一个链表 这里由于链表// 如果太长就会树化成红黑树,以下是判断p也就是桶里放的是不是红黑树else if (p instanceof TreeNode)// 是红黑树 我们就把节点放入红黑树 注意:这里也不是一定插入到树中,// 因为如果我们要插入的元素和红黑树中某个节点的key相同的话,也会考虑// 新值换旧值的问题e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {// 跳到这 说明p不是树,而是链表 binCount用来记录链表中元素的个数,那么// 为啥要记录链表中元素的个数呢?主要判断链表是否需要树化成红黑树for (int binCount = 0; ; ++binCount) {// e的后一个节点为空 那么直接挂上我们要插入的元素if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);// TREEIFY_THRESHOLD 是树化的阈值且其值为8// 这里要注意:我们要插入的节点p是还没有加到binCount中的// 也就是说这里虽然binCount>=7就可以树化,其实真正的树化// 条件是链表中元素个数大于等于8if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}// 待插入的key在链表中找到了,记录下来然后退出if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}// 说明找到了key相同的元素if (e != null) { // existing mapping for keyV oldValue = e.value;// 判断是否需要旧值换新值,默认情况下是允许更换的if (!onlyIfAbsent || oldValue == null)e.value = value;// 这个方法点进去就是个空方法,主要是为了给继承HashMap的// LinkedHashMap服务的afterNodeAccess(e);return oldValue;}}// 修改次数+1++modCount;// 看下达到扩容的阀值没if (++size > threshold)// 扩容 ,在本方法的前面需要初始化的时候也出现过resize();// 这个方法同样也是为LinkedHashMap服务的afterNodeInsertion(evict);// 没找到元素 就返回空return null;}

6、获取元素的方法时怎么实现的?

使用hash值去找桶的位置:

2831cf3b420c164f1c9e634d13582915.png
 final Node<K,V> getNode(int hash, Object key) {Node<K,V>[] tab; Node<K,V> first, e; int n; K k;// 桶不为空 并且桶的元素大于0 同时定位的位置元素还不为空 那就顺藤摸瓜if ((tab = table) != null && (n = tab.length) > 0 &&(first = tab[(n - 1) & hash]) != null) {// 第一个元素是不是我们要找的啊?判断一下,是就返回if (first.hash == hash && // always check first node((k = first.key) == key || (key != null && key.equals(k))))return first;if ((e = first.next) != null) {// 第一个元素不是我们要找的,而且后面还接着元素 判断一下是不是树if (first instanceof TreeNode)// 是树 按照树的获取节点方法去获取return ((TreeNode<K,V>)first).getTreeNode(hash, key);// 到这说明是链表了 那就按照链表的方式去循环do {if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}}return null;}

7、最后插播一下HashMap中的属性

 // 初始容量1向左移动4位为16static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16// 最大容量1向左移30位static final int MAXIMUM_CAPACITY = 1 << 30;// 加载因子 也就是桶大小使用要是超过0.75 那么就要考虑扩容了static final float DEFAULT_LOAD_FACTOR = 0.75f; //  链表太长 要变树的阀值static final int TREEIFY_THRESHOLD = 8;// 树变成链表的阀值static final int UNTREEIFY_THRESHOLD = 6;// TREEIFY_THRESHOLD达到8也不一定树化,还要容量达到64static final int MIN_TREEIFY_CAPACITY = 64;

下一期我们对今天讲的put、get方法内涉及到的重要的方法进行讲解。拜了个拜!

大量面试经验以及学习资料书籍请关注微信公众号:AVAJ

回复"offer"进行获取

365篇大厂java面经 你想要的我这里都有

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

对分查找的最多次数_「剑指offer题解」数组中出现次数超过一半的数字

关注我——个人公众号&#xff1a;后端技术漫谈我目前是一名后端开发工程师。主要关注后端开发&#xff0c;数据安全&#xff0c;网络爬虫&#xff0c;物联网&#xff0c;边缘计算等方向。原创博客主要内容Java知识点复习全手册Leetcode算法题解析剑指offer算法题解析SpringClo…

rabbitmq导出队列_消息队列BCMQ在大云运维管理平台BCDeepWatch中的应用

友情提示&#xff1a;全文约2600字&#xff0c;预计阅读时间12分钟摘要消息队列作为重要的中间件&#xff0c;广泛用于分布式系统中各子系统间的异步解耦&#xff1b;本文主要介绍了大云消息队列中间件BC-MQ在BC-DeepWatch中的应用案例。一、消息队列应用场景简介消息队列是分布…

【编译原理】如何编写BNF?

此篇文章承接上一篇&#xff1a;【编译原理】理解BNF 前言 理解了BNF&#xff0c;就能实现代码解析了吗&#xff1f;还有点早&#xff0c;因为理解了BNF&#xff0c;还要会写BNF。实际上&#xff0c;BNF实现有固定的模式&#xff0c;也有现成的工具&#xff0c;比如可以使用ya…

python 当前时间减一个月_python排序了解一下

排序是每个开发人员都需要掌握的技能。排序是对程序本身有一个全面的理解。不同的排序算法很好地展示了算法设计上如何强烈的影响程序的复杂度、运行速度和效率。今天的文章和谈谈大家都熟悉的各种排序使用 Python 如何实现&#xff0c;废话就不多说啦&#xff0c;开干&#xf…

【转】4.1触碰jQuery:AJAX异步详解

传送门&#xff1a;异步编程系列目录…… 示例源码&#xff1a;触碰jQuery&#xff1a;AJAX异步详解.rar AJAX 全称 Asynchronous JavaScript and XML&#xff08;异步的 JavaScript 和 XML&#xff09;。它并非一种新的技术&#xff0c;而是以下几种原有技术的结合体。 1) 使…

QStackedWidget实现自适应紧凑布局

前言 本文提出了一种使QStackedWidget尺寸根据内容自适应调整的解决方法。 问题提出 我们知道&#xff0c;QStackedWidget可以包含多个可切换的子窗口。多个子窗口的高度不一样时&#xff0c;此时将QStackedWidget放在一个垂直布局中&#xff0c;所有子窗口会保持和最高的子…

linux查看tcl版本_查看Linux内核版本的方法有几个?你也是这样操作吗?

请关注本头条号&#xff0c;每天坚持更新原创干货技术文章。如需学习视频&#xff0c;请在微信搜索公众号“智传网优”直接开始自助视频学习1. 前言内核是操作系统的核心组件。 它管理系统的资源&#xff0c;是计算机硬件和软件之间的桥梁。您可能因多种原因需要确切知道GNU / …

【转】4.2使用jQuery.form插件,实现完美的表单异步提交

传送门&#xff1a;异步编程系列目录…… 示例下载&#xff1a;使用jQuery.form插件&#xff0c;实现完美的表单异步提交.rar 抓住6月份的尾巴&#xff0c;今天的主题是 今天我想介绍的是一款jQuery的插件&#xff1a;Jquery.form.js 官网。 通过该插件&#xff0c;我们可以非常…

什么方式可以通过影子系统传播恶意代码_将恶意代码隐藏在图像中:揭秘恶意软件使用的隐写术...

概述本周&#xff0c;许多Facebook用户都会发现&#xff0c;一些用户发布图片上出现了原本应该隐藏的图像标签。由此可以证明&#xff0c;图像可以携带大量表面上不可见的数据。实际上&#xff0c;Facebook和Instagram所使用的图片元数据与恶意攻击者制作的特制图像相比显得非常…

无法嵌入互操作类型 请改用适用的接口_西门子COMOS软件开发定制学习7-嵌入谷歌浏览器内核...

首先需要声明的是&#xff0c;本篇并非COMOS实用案例&#xff0c;只是希望借此让大家了解&#xff0c;如何使用微软的WPF和C#语言开发COMOS插件。首先看下效果图功能说明&#xff1a;拖拽COMOS设备至定制的浏览器&#xff0c;自动根据设备的名称和其制造商参数值&#xff0c;搜…

【转】C#与C++的发展历程第一 - 由C#3.0起

C#5.0作为第五个C#的重要版本&#xff0c;将异步编程的易用度推向一个新的高峰。通过新增的async和await关键字&#xff0c;几乎可以使用同编写同步代码一样的方式来编写异步代码。 本文将重点介绍下新版C#的异步特性以及部分其他方面的改进。同时也将介绍WinRT程序一些异步编…

【转】5.2高性能IO模型浅析

服务器端编程经常需要构造高性能的IO模型&#xff0c;常见的IO模型有四种&#xff1a; &#xff08;1&#xff09;同步阻塞IO&#xff08;Blocking IO&#xff09;&#xff1a;即传统的IO模型。 &#xff08;2&#xff09;同步非阻塞IO&#xff08;Non-blocking IO&#xff0…

vba 修改文本文档 指定行_VBA程序报错,用调试三法宝,bug不存在的

如果把VBA比作一门刀法&#xff0c;那么经过前面内容的操练&#xff0c;大家已经掌握了很多实用的招式。如果我们在刀法招式的基础之上&#xff0c;再掌握更多的“磨刀”心法&#xff0c;那么我们的刀用起来才会又好又快。所以今天主要和大家分享——VBA“磨刀”心法之程序调试…

mqtt协议详解_IoT物联网设备上云技术方案详解

随着传感器和通信技术的不断发展&#xff0c;物联网行业方兴未艾&#xff0c;业务链路涉及数据采集&#xff0c;通信连接&#xff0c;数据存储&#xff0c;数据可视化&#xff0c;洞察&#xff0c;行动决策。但&#xff0c;在实施过程中&#xff0c;碎片化的设备端通信连接难题…

【转】基于WebSocketSharp 的IM 简单实现

websocket-sharp 是一个websocket的C#实现&#xff0c;支持.net 3.5及以上来开发服务端或者客户端。本文主要介绍用websocket-sharp来做服务端、JavaScript做客户端来实现一个简单的IM。 WebSocketBehavior WebSocketBehavior是核心对象&#xff0c;他包含了OnOpen,OnMessage…

【转】极限编程一览

极限编程&#xff08;XP&#xff09;起源始于1990年代。当时肯特布莱克&#xff08;Kent Black&#xff09;在戴姆勒克莱斯勒&#xff08;DaimlerChrysler&#xff09;处理项目时&#xff0c;试图寻找一种更好的软件开发方法。他的创立新方法后来被称为极限编程方法论&#xff…

mysql 关联更新_跳出初学MySQL知识的原理整理(一)

一、基础架构MySQL 可以分为 Server 层和存储引擎层两部分。Server 层包括连接器、查询缓存、分析器、优化器、执行器等&#xff0c;所有跨存储引擎的功能都在这一层实现&#xff0c;比如存储过程、触发器、视图等。而存储引擎层负责数据的存储和提取。支持 InnoDB、MyISAM等多…

【转】TcpListener和tcpclient使用

前段时间公司项目中遇着需要做文件的远程传输&#xff0c;场景是用户通过网页选择一些文件&#xff0c;然后提交请求到服务器&#xff0c;同时把请求标识传递给本机的TCP文件传输端&#xff1b;服务器收到请求后在服务器端创建任务生成保存文件的路径同时通知文件传输端开始传文…

sleep期间读取所有_ceph部分数据所有副本先后故障的抢救

半天河网易游戏高级运维工程师&#xff0c;主要负责云存储的运维&#xff1b;一个既希望跟业务聊又喜欢能够默默在后面忙活的普通运维人。背景故障现场故障恢复故障恢复分析第一种方式&#xff1a;物理磁盘对拷第二种方式&#xff1a;服务启动时跳过故障扇区来避免异常退出解决…

【转】有限状态机用法教程

如博文无法正常显示&#xff0c;请访问原文地址&#xff1a; https://blog.csdn.net/ChinarCSDN/article/details/82263126 有限状态机用法教程 文章目录 有限状态机用法教程 [toc]1Finite-state machine —— 有限状态机2Foreword —— 前言()3Example —— 示例4Moltimode —…