面试级解析HashMap
------------恢复内容开始------------
在介绍HashMap之前,有必要先给大家介绍一些参数的概念
HashMap的最大容量,capacity译为容量,capacity就是指HashMap中bucket(桶)的数量。官方给的注解必须为2的幂。默认为1<<4(ps:这里的<<是位移运算符),每次扩容都会扩容为原来的2倍。总之,容量都是2的幂。
1/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
ps:位移运算符: <<左移运算符,>>右移运算符,还有不带符号的位移运算
计算过程以1<<4为例,首先把1转为二进制数字0000 0001
然后将上面的二进制数字向左移动30位后面补0得到0001 0000
最后将得到的二进制数字转回对应类型的十进制,运行结果为:16
HashMap的最大容量,默认值为1<<30, 即1073741824
/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
public static void main(String[] args) {
int i =1;
System.out.println(i << 30);
}

loadFactor译为装载因子,装载因子用来衡量HashMap的拥挤程度。loadFactor的默认值为0.75f。当HashMap里面容纳的元素已经达到HashMap容量的75%时,表示HashMap太挤了,需要扩容,在HashMap的构造器中可以定制loadFactor。
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
树化参数
/**
* 树化阀值,默认值为8
*/
static final int TREEIFY_THRESHOLD = 8;
/**
* 树退化阀值,默认为6
*/
static final int UNTREEIFY_THRESHOLD = 6;
/**
* 最小树化HashMap的capacity(容量),默认为64
*/
static final int MIN_TREEIFY_CAPACITY = 64;
size
HashMap中实际存在的键值对的数量(为链表和树中的KV的总和)
/**
* The number of key-value mappings contained in this map.
*/
transient int size;
threshold(扩容阀值)
threshold表示当HashMap的size大于threshold时会执行resize操作。
threshold=capacity*loadFactor
/**
* The next size value at which to resize (capacity * load factor).
* @serial
*/
int threshold;
接下来,我们通过一场小型面试来探究下HashMap的相关知识:
面试小会场:
面试官:你能跟我聊聊HashMap吗?
小明:HashMap存储键值对实现快速存取,允许为null,key值不可重复,若key值重复则覆盖;非同步,线程不安全;底层是hash表,不保证有序(比如插入的顺序)
面试官:那你能跟我聊聊它的结构和底层原理吗?
小明:HashMap是我们平时常用的数据结构,jdk1.7之前由数组和链表组合构成的数据结构。现在是由数组、链表加红黑树构成的数据结构。数组里面每个地方都存了Key-Value这样的实例,hashMap在put插入数据的时候会根据key去hash计算index的值,如果散列表为空时,调用resize()初始化散列表,如果没有发生hash碰撞,直接添加元素到散列表中去
如图:我们通过哈希函数计算出插入("name","张三")的位置, index = HashCode(Key) & (Length - 1)计算出来的index为2

在有限的数组中,我们使用hash会有一定的概率hash到一个值上
**如果发生了碰撞(hashCode值相同),进行三种判断 **
1.1:若key地址相同或者equals后内容相同,则替换旧值
1.2:如果是红黑树结构,就调用树的插入方法
1.3:链表结构,循环遍历直到链表中某个节点为空,尾插法进行插入,插入之后判断链表个数是否到达变成红黑树的树化阙值 8 ;也可以遍历到有节点与插入元素的哈希值和内容相同,进行覆盖。

所以在HashMap中只能使用引用类型(如Integer、String)来作为key,因为这些类已经很规范的覆写了hashCode()以及equals()方法。当我们去get时,对key的hashCode进行hashing,与运算计算下标获取bucket(桶)位置,如果在bucket桶的首位上就可以找到就直接返回,否则在树中找或者链表中遍历找,如果有hashCode相同,则利用equals方法去遍历链表查找节点
面试官:那你能说一下为什么要引入红黑树吗?
小明:JDK 1.8 以前 HashMap 的实现是 数组+链表,即使哈希函数取得再好,也很难达到元素百分百均匀分布。当 HashMap 中有大量的元素都存放到同一个桶中时,这个桶下有一条长长的链表,这个时候 HashMap 就相当于一个单链表,假如单链表有 n 个元素,遍历的时间复杂度就是 O(n),完全失去了它的优势。针对这种情况,JDK 1.8 中引入了 红黑树(查找时间复杂度为 O(logn))来优化这个问题。
面试官:那你最后在说一下HashMap是如何扩容的吧

小明:如图,假设此时有一个容量为64的HashMap。1号桶内加上挂载的红黑树一共是46个KV,2号桶内加上链表上一共是3个KV,所以该hashmap实例的size = 46 +3 =49。此hashaMap的threshold(扩容阈值)=capacity(当前容量64) * loadfactory(负载因子 0.75) = 48 。由公式++size> load factor * capacity可知此时49>48,所以会扩容。
扩容分为两步
- 扩容:创建一个新的Entry空数组,长度是原数组的2倍。
- ReHash:遍历原Entry数组,把所有的Entry重新Hash到新数组。
ad factor * capacity可知此时49>48,所以会扩容。
扩容分为两步
- 扩容:创建一个新的Entry空数组,长度是原数组的2倍。
- ReHash:遍历原Entry数组,把所有的Entry重新Hash到新数组。
面试官:今天表现不错,等复试吧~
------------恢复内容结束------------
面试级解析HashMap的更多相关文章
- 知名互联网公司校招 Java 开发岗面试知识点解析
天之道,损有余而补不足,是故虚胜实,不足胜有余. 本文作者在一年之内参加过多场面试,应聘岗位均为 Java 开发方向.在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点. 主要包括以下几 ...
- Java 面试知识点解析(四)——版本特性篇
前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...
- Java 面试知识点解析(一)——基础知识篇
前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...
- Java 面试知识点解析(二)——高并发编程篇
前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...
- Java 面试知识点解析(六)——数据库篇
前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...
- 深入解析HashMap、HashTable
集合类之番外篇:深入解析HashMap.HashTable Java集合类是个非常重要的知识点,HashMap.HashTable.ConcurrentHashMap等算是集合类中的重点,可谓“重中之 ...
- 《Java面试全解析》505道面试题详解
<Java面试全解析>是我在 GitChat 发布的一门电子书,全书总共有 15 万字和 505 道 Java 面试题解析,目前来说应该是最实用和最全的 Java 面试题解析了. 我本人是 ...
- 《Java面试全解析》1000道面试题大全详解(转)
<Java面试全解析>1000道 面试题大全详解 本人是 2009 年参加编程工作的,一路上在技术公司摸爬滚打,前几年一直在上海,待过的公司有 360 和游久游戏,因为自己家庭的原因,放弃 ...
- 深度解析HashMap底层实现架构
摘要:分析Map接口的详细使用以及HashMap的底层是如何实现的? 本文分享自华为云社区<[图文并茂]深度解析HashMap高频面试及底层实现结构![奔跑吧!JAVA]>,原文作者:灰小 ...
随机推荐
- 下载器Folx扩展程序支持哪些浏览器
Folx使用多线程的下载方式大大提升了下载的速度,可以完全替代浏览器自带的下载工具,使下载文件的管理更加简单高效.但是,必须给浏览器安装Folx扩展程序,才能使用Folx下载页面链接. Folx在偏好 ...
- 关于Vegas制作黑白负片爆闪效果的教程分享
作为一款视频剪辑软件,Vegas界面简洁,操作难度低,比较容易上手,今天小编就带大家了解Vegas制作超级炫酷的黑白负片爆闪效果的操作过程. 1.导入视频 首先,双击打开视频剪辑软件Vegas Pro ...
- Java复数的定义与描述
1 //4.复数的定义与描述 2 package test; 3 4 import java.util.Scanner; 5 6 public class complex {//复数类 7 doubl ...
- redis 一致性分析
转载: https://blog.csdn.net/qq32933432/article/details/108690254
- Arcgis基于高程(DEM)计算地形湿度指数(TWI),以及坡度(Slope)度单位转换为弧度
以30m*30m分辨率的图层为例 一.基于表面工具箱Surface计算Slope 1.如下图输入图层DEM,输出Slope 2.单位转换: Scale_slope=Slope*pi/180 二.基于水 ...
- JDk8的新特性-流和内部iteration
JDK8到今天已经出了好几年了 但是在公司能用到新特性的地方还是很少, 去年的时候当时项目老大要求我们用最新的写法来写Java 刚开始看到用stream写出来的代码一脸懵逼,内心就在想 这是Jav ...
- 16_Android的数据存储_ SharedPreference、XML和JSON
1. Android读写首选项 1.1 SharedPreferences SharedPreferences 是一种轻型的数据存储方式,它的本质是基于XML文件存储Key-Value键值对数据,通常 ...
- for循环与while循环
1.两中循环的语法结构 for循环结构: for(表达式1;表达式2;表达式3) { 执行语句; } while循环结构: while(表达式1) { 执行语句; } 2.两者区别: 应用场景:由于f ...
- 色相偏移 HueShift ASE
色相偏移可以改变颜色色调,unity ASE没有参考UE4写个,原理很简单,将颜色向量绕(1,1,1)旋转,就可以得到不同色调的颜色. https://zhuanlan.zhihu.com/p/677 ...
- Docker 跨平台在 netCore 中的从入门到部署
前言 从题目我们可以看的出,今天是五部曲的第三部,你可能会好奇,为啥没有见到前两部呢?这里我简单说下: 1.跨平台第一部曲:MySql 如果你看我的所有开源项目,应该能发现我已经全部迁移到了Mysql ...