HashMap 底层实现原理

HashMap 底层实现原理要了解 HashMap 的底层实现原理 我们首先要对 HashMap 的部分底层源码进行分析 publicclassH K V extendsAbstr K V implementsMa K V Cloneable Serializable 我们可以看出 HashMap 继承了 AbstractMap 实现了 Map Cloneable Serializable 接口 staticfinali I K V K V K V

要了解HashMap的底层实现原理,我们首先要对HashMap的部分底层源码进行分析

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable

我们可以看出HashMap继承了AbstractMap,实现了Map,Cloneable,Serializable接口。

HashMap 底层实现原理

 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

HashMap的默认初始容量(必须是2的幂),它的值是1左移4位,也就是16

static final int MAXIMUM_CAPACITY = 1 << 30;

HashMap的最大容量,如果任何一个带参数的构造函数指定了较大的值,就会使用它来比较,而且值必须是2的幂,并且小于1左移30位,2的30次方,也就是

 static final float DEFAULT_LOAD_FACTOR = 0.75f;

HashMap默认的加载因子,因为从上可知,HashMap的默认初始容量是16,当HashMap的实际容量达到16*0.75,就是12,HashMap会自动扩容。

 static final int TREEIFY_THRESHOLD = 8;

HashMap底层链表转换成红黑树的临界值,当链表的长度大于8时,会自动转化成红黑树。

static final int UNTREEIFY_THRESHOLD = 6;

HashMap底层红黑树转化成链表的临界值,当红黑树的长度小于6时,红黑树又会自动转换成链表。

static final int MIN_TREEIFY_CAPACITY = 64;

HashMap转化成树结构的最小容量,因为HashMap底层时数组+链表+红黑树实现的,HashMap的容量大于64时,会自动转换成树结构,也就是数组的长度大于64时,也会转换成红黑树。


以下是HashMap的静态内部类

HashMap 底层实现原理

static class Node<K,V> implements Map.Entry<K,V> { final int hash;//若放入的节点key的hash值(若key所在的类未进行重写hash()方法的重写,则为Object的hash()方法) 定义数组索引的位置 final K key;//放入节点的key V value;//放入节点的value Node<K,V> next;//此节点的下一个节点 Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } public final K getKey() { return key; } public final V getValue() { return value; } public final String toString() { return key + "=" + value; } public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value); } public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } public final boolean equals(Object o) { if (o == this) return true; if (o instanceof Map.Entry) { // 判断key和value是否都相等 Map.Entry<?,?> e = (Map.Entry<?,?>)o; if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) // 如果key和value都相等,就返回true return true; } // 如果key或者value不相等,就返回false return false; } } 

继续往下看

HashMap 底层实现原理

static final int hash(Object key) { // 计算key的hash值 int h; // 1.先拿到key的hashCode值; 2.将hashCode的高16位参与运算 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } 
static Class<?> comparableClassFor(Object x) { // 1.判断x是否实现了Comparable接口 if (x instanceof Comparable) { Class<?> c; Type[] ts, as; Type t; ParameterizedType p; // 2.校验x是否为String类型 if ((c = x.getClass()) == String.class) // bypass checks return c; if ((ts = c.getGenericInterfaces()) != null) { // 3.遍历x实现的所有接口 for (int i = 0; i < ts.length; ++i) { // 4.如果x实现了Comparable接口,则返回x的Class if (((t = ts[i]) instanceof ParameterizedType) && ((p = (ParameterizedType)t).getRawType() == Comparable.class) && (as = p.getActualTypeArguments()) != null && as.length == 1 && as[0] == c) // type arg is c return c; } } } return null; }

HashMap 底层实现原理

 / * HashMap的成员变量数组 */ transient Node<K,V>[] table; / * 存储的是entrySet,其实里面的每个元素就是HashMap的每个节点 */ transient Set<Map.Entry<K,V>> entrySet; / * HashMap中已存元素的个数 size */ transient int size; / * HashMap被修改的次数 put remove 操作的次数 */ transient int modCount; //阈值 capacity*loadFactor 或者是将要初始化扩容的容量值 int threshold; / * 负载因子 */ final float loadFactor; 

简单看一下底层源码,我们可以做出以下总结:

HashMap的初始容量是16,默认加载因子是0.75,扩容按照原始容量的2倍扩容,可以存储null值和null键,因为没有加锁,当多个线程同时操作一个hashmap就可能出现不安全的情况,所以线程也是不安全的,底层是由数组+链表+红黑树实现。

当添加一个元素(key-value)时,就首先计算元素key的hash值,以此确定插入数组中的位置,但是可能存在同一hash值的元素,这时就添加到同一hash值的元素的后面,他们在数组的同一位置,但是形成了链表,同一各链表上的Hash值是相同的,所以说数组存放的是链表。而当链表长度大于8时,链表就转换为红黑树,以及当数组的长度大于64时,也会自动转换成红黑树,这样大大提高了查找的效率。

通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node(节点)添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着key和链表上每个节点的key进行equals。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals的结果返回了true,那么这个节点的value将会被覆盖。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/233677.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • pycharm安装步骤2021_2021年上映时间表

    pycharm安装步骤2021_2021年上映时间表安装PyCharm2022教程下载安装PyCharm安装Python配置PyCharm环境使用PyCharmPyCharm界面介绍一、下载安装PyCharmpycharm在官网上的下载地址:2.专业版,社区版。建议安装专业版。下载文件会显示3.单击“安装”修改安装路径。建议安装磁盘C以外的位置。修改后,单击“下一步”。4.这里功能选项,全部勾选,或者根据自己需求选择;5.接下来,单击“安装”打开安装界面。二、安装Python如果您以前没有下载过Python解释器,则需

    2022年8月28日
    1
  • 分子模拟软件amber_使用Amber创建小分子与蛋白质复合蛋白的坐标和拓扑文件

    分子模拟软件amber_使用Amber创建小分子与蛋白质复合蛋白的坐标和拓扑文件复合蛋白amber坐标和拓扑文件的创建作者:朱宁来源:大科研小分享前言分子动力学(MolecularDynamics,MD)是一门结合物理,数学和化学的综合技术。目前主流分子动力学软件有NAMD、GROMACS、AMBER等。AMBER分子动力学程序包是由加州圣弗兰西斯科大学(UCSF)的PeterAKollman和其同事编写的,程序很全,大约包含60多个程序,相互协调工…

    2022年5月26日
    46
  • Laravel5.2中Eloquent与DB类的区别是什么?

    Laravel5.2中Eloquent与DB类的区别是什么?

    2021年11月9日
    40
  • J2EE是什么意思_main()函数是java程序的执行入口

    J2EE是什么意思_main()函数是java程序的执行入口j2ee   J2EE简介  J2EEJava2平台企业版(Java2Platform,EnterpriseEdition)   J2EE是一套全然不同于传统应用开发的技术架构,包含许多组件,主要可简化且规范应用系统的开发与部署,进而提高可移植性、安全与再用价值。   J2EE核心是一组技术规范与指南,其中所包含的各类组件、服务架构及技术层次,均有共通的标准及规格,让各种依

    2022年10月11日
    2
  • Nacos 2.0_一个数的0倍是多少

    Nacos 2.0_一个数的0倍是多少点击关注公众号,Java干货及时送达3月20号,Nacos2.0.0正式发布了!Nacos简介:“一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。通俗点讲,Nacos…

    2022年9月20日
    2
  • Python 万能代码模版:爬虫代码篇「建议收藏」

    Python 万能代码模版:爬虫代码篇「建议收藏」你好,我是悦创。很多同学一听到Python或编程语言,可能条件反射就会觉得“很难”。但今天的Python课程是个例外,因为今天讲的**Python技能,不需要你懂计算机原理,也不需要你理解复杂的编程模式。**即使是非开发人员,只要替换链接、文件,就可以轻松完成。并且这些几个实用技巧,简直是Python日常帮手的最佳实践。比如:爬取文档,爬表格,爬学习资料;玩转图表,生成数据可视化;批量命名文件,实现自动化办公;批量搞图,加水印、调尺寸。接下来,我们就逐一用Python实

    2022年5月26日
    77

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号