广告
返回顶部
首页 > 资讯 > 精选 >如何解读Java HashMap核心源码
  • 186
分享到

如何解读Java HashMap核心源码

2023-06-17 06:06:34 186人浏览 八月长安
摘要

这期内容当中小编将会给大家带来有关如何解读Java HashMap核心源码,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。对HashMap实现的源码进行简单的分析。 所使用的HashMap源码的版本信息如下

这期内容当中小编将会给大家带来有关如何解读Java HashMap核心源码,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

对HashMap实现的源码进行简单的分析。 所使用的HashMap源码的版本信息如下:

一.概述

在Java中每一个对象都有一个哈希码,这个值可以通过hashCode()方法获得。hashCode()的值和对象的equals方法息息相关,是两个对象的值是否相等的依据,所以当我们覆盖一个类的equals方法的时候也必须覆盖hashCode方法。

例如String的hashCode方法为:

public int hashCode() {int h = hash;if (h == 0) {int off = offset;char val[] = value;int len = count;for (int i = 0; i < len; i++) {h = 31*h + val[off++];}hash = h;}return h;}

可以看得出,一个字符串的哈希值为s[0]31n-1 + s[1]31n-2 + &hellip; + s[n-1],是一个整数。也就是说所有的字符串可以通过hashCode()将其映射到整数的区间中,由于在java中整数的个数是有限的(四个字节有正负,***位为符号位-231 ~ 231 -1),当s[0]31n-1 + s[1]31n-2 +  &hellip; +  s[n-1]足够大的时候可能会溢出,导致其变成负值。从上面的情况我们可以看出两个不同的字符串可能会被映射到同一个整数,发生冲突。因此java的开 发人员选择了31这个乘数因子,尽量使得各个字符串映射的结果在整个java的整数域内均匀分布。

谈完java对象的哈希码,我们来看看今天的主角HashMap,HashMap可以看作是Java实现的哈希表。HashMap中存放的是 key-value对,对应的类型为java.util.HashMap.Entry,所以在HashMap中数据都存放在一个Entry引用类型的数组 table中。这里key是一个对象,为了把对象映射到table中的一个位置,我们可以通过求余法来,所以我们可以使用 [key的hashCode %  table的长度]来计算位置(当然在实际操作的时候由于需要考虑table上的key的均匀分布可能需要对key的hashCode做一些处理)。

二.源码解析

相关属性 首先肯定是需要一个数组table,作为数据结构的骨干。

transient Entry[] table;

这边定义了一个Entry数组的引用。 继续介绍几个概念把

capacity容量 是指数组table的长度
loadFactor 装载因子,是实际存放量/capacity容量 的一个比值,在代码中这个属性是描述了装载因子的***值,默认大小为0.75
threshold(阈值)代表hashmap存放内容数量的一个临界点,当存放量大于这个值的时候,就需要将table进行夸张,也就是新建一个两倍大的数组,并将老的元素转移过去。threshold = (int)(capacity * loadFactor);

put方法详解

public V put(K key, V value) {        if (key == null)            return putForNullKey(value);        int hash = hash(key.hashCode());        int i = indexFor(hash, table.length);        for (Entry<K,V> e = table[i]; e != null; e = e.next) {            Object k;            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {                V oldValue = e.value;                e.value = value;                e.recordAccess(this);                return oldValue;            }        }        modCount++;        addEntry(hash, key, value, i);        return null;    }

在HashMap中我们的key可以为null,所以***步就处理了key为null的情况。
当key为非null的时候,你也许会认为:恩,直接和table长度相除取模吧,但是这里没有,而是又好像做了一次哈希,这是为什么呢?这个还得先看indexFor(hash, table.length)方法,这个方法是决定存放位置的

static int indexFor(int h, int length) {        return h & (length-1);    }

明眼的都可以发现,因为在HashMap中table的长度为2n (我们把运算都换成二进制进行考虑),所以h &  (length-1)就等价于h%length,这也就是说,如果对原本的hashCode不做变换的话,其除去低length-1位后的部分不会对 key在table中的位置产生任何影响,这样只要保持低length-1位不变,不管高位如何都会冲突,所以就想办法使得高位对其结果也产生影响,于是 就对hashCode又做了一次哈希

static int hash(int h) {        // This function ensures that hashCodes that differ only by        // constant multiples at each bit position have a bounded        // number of collisions (approximately 8 at default load factor).        h ^= (h >>> 20) ^ (h >>> 12);        return h ^ (h >>> 7) ^ (h >>> 4);    }

当找到key所对应的位置的时候,对对应位置的Entry的链表进行遍历,如果以及存在key的话,就更新对应的value,并返回老的 value。如果是新的key的话,就将其增加进去。modCount是用来记录hashmap结构变化的次数的,这个在hashmap的fail- fast机制中需要使用(当某一个线程获取了map的游标之后,另一个线程对map做了结构修改的操作,那么原先准备遍历的线程会抛出异常)。 addEntry的方法如下

void addEntry(int hash, K key, V value, int bucketIndex) {    Entry<K,V> e = table[bucketIndex];        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);        if (size++ >= threshold)            resize(2 * table.length);    }

get方法

public V get(Object key) {        if (key == null)            return getForNullKey();        int hash = hash(key.hashCode());        for (Entry<K,V> e = table[indexFor(hash, table.length)];             e != null;             e = e.next) {            Object k;            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))                return e.value;        }        return null;    }

get方法其实就是将key以put时相同的方法算出在table的所在位置,然后对所在位置的链表进行遍历,找到hash值和key都相等的Entry并将value返回。

上述就是小编为大家分享的如何解读Java HashMap核心源码了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网精选频道。

--结束END--

本文标题: 如何解读Java HashMap核心源码

本文链接: https://www.lsjlt.com/news/287548.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何解读Java HashMap核心源码
    这期内容当中小编将会给大家带来有关如何解读Java HashMap核心源码,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。对HashMap实现的源码进行简单的分析。 所使用的HashMap源码的版本信息如下...
    99+
    2023-06-17
  • Java SpringBoot核心源码详解
    目录SpringBoot源码主线分析1.SpringBoot启动的入口2.run方法3.SpringApplication构造器4.run方法总结SpringBoot源码主线分析 我...
    99+
    2022-11-12
  • 如何用源码分析Java HashMap实例
    本篇文章为大家展示了如何用源码分析Java HashMap实例,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。引言HashMap在键值对存储中被经常使用,那么它到底是如何实现键值存储的呢?一 Entr...
    99+
    2023-06-17
  • 如何理解Java Socket聊天程序核心代码
    如何理解Java Socket聊天程序核心代码,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Java Socket聊天程序在编写的时候需要我们注意很多的事情,本程...
    99+
    2023-06-17
  • 如何理解SpringBoot核心运行原理和运作原理源码
    如何理解SpringBoot核心运行原理和运作原理源码,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。SpringBoot核心运行原理Spr...
    99+
    2022-10-19
  • Java+Linux内核源码之如何理解多线程之进程
    这篇文章主要讲解了“Java+Linux内核源码之如何理解多线程之进程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java+Linux内核源码之如何理解多线程之进程”吧!Linux 内核如...
    99+
    2023-06-15
  • 如何理解golang里面的读写锁实现与核心原理
    如何理解golang里面的读写锁实现与核心原理,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。基础筑基读写锁的特点读写锁区别与互斥锁的主要区别就是读锁之间是共享的...
    99+
    2023-06-19
  • 从零开始学习 Java:简单易懂的入门指南之HashMap及TreeMap源码解读(二十四)
    HashMap及TreeMap源码解读 HashMap源码TreeMap源码 HashMap源码 1.看源码之前需要了解的一些内容Node[] table 哈希表结构中数组的名字DEF...
    99+
    2023-09-14
    学习 java 哈希算法 开发语言 算法 数据结构 链表
  • ​Javac编译器如何读取Java源代码
    这篇文章给大家分享的是有关Javac编译器如何读取Java源代码的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Javac编译器读取Java源代码,并将其编译成字节代码,调用Javac的命令行如下:  C:>...
    99+
    2023-06-03
  • PostgreSQL 源码解读(180)- 内核研发#4(如何实现自定义系统函数)
    本节以实现Oracle中的add...
    99+
    2022-10-18
  • Java基础之如何理解Object源码
    本篇内容主要讲解“Java基础之如何理解Object源码”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java基础之如何理解Object源码”吧!getClasspublic fina...
    99+
    2023-06-15
  • 如何理解Java SynDemo对象源代码
    本篇文章为大家展示了如何理解Java SynDemo对象源代码,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java SynDemo对象一直在我们的语言使用中使用,其实在不断的学习中我们还是在源代码...
    99+
    2023-06-17
  • 如何理解低代码开发平台核心组件集成和协同
    这篇文章主要讲解了“如何理解低代码开发平台核心组件集成和协同”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解低代码开发平台核心组件集成和协同”吧!低代...
    99+
    2022-10-19
  • Java中如何读取和解码二维码文件?
    在现代社会中,二维码(QR码)已经成为了一种非常流行的信息扫描方式。我们可以使用手机或其他设备扫描二维码,获取其中的信息。而在Java中,我们也可以轻松地读取和解码二维码文件。本文将介绍如何在Java中读取和解码二维码文件。 一、引入相关依...
    99+
    2023-07-05
    二维码 面试 文件
  • 从Kafka Monitor源码解读看如何做好黑盒监控
    这篇文章给大家介绍从Kafka Monitor源码解读看如何做好黑盒监控,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。首先带来的是“监控”专题系列。众所周知,监控分为黑盒和白盒监控,黑盒监控是通过模拟外部用户对其可见的...
    99+
    2023-06-05
  • 如何以武侠形式理解Java LinkedList源码
    如何以武侠形式理解Java LinkedList源码,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。一、LinkedList 的剖白大家好,我是 LinkedLi...
    99+
    2023-06-25
  • 如何理解Java容器中Map的源码分析
    本篇文章为大家展示了如何理解Java容器中Map的源码分析,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。如果没有特别说明,以下源码分析基于 JDK 1.8。一、HashMap为了便于理解,以下源码分...
    99+
    2023-06-05
  • 如何理解Java容器中ArrayList的源码分析
    这篇文章给大家介绍如何理解Java容器中List的源码分析,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。如果没有特别说明,以下源码分析基于 JDK 1.8。一、ArrayList1. 概览实现了 RandomAcces...
    99+
    2023-06-05
  • 如何通过源码了解Java的自动装箱拆箱详解
    目录什么叫装箱 & 拆箱?首先看一段代码装箱(valueOf())为什么要有[-128,127]的缓存?为什么是[-128,127]?自动装箱带来的性能问题小总结拆箱(int...
    99+
    2022-11-13
  • Java读取resources中资源文件路径以及jar中文件无法读取如何解决
    今天小编给大家分享的是Java读取resources中资源文件路径以及jar中文件无法读取如何解决,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。Java读取resources中资源文...
    99+
    2023-07-06
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作