Java 7 HashMap源码解析

HashMap源码(JDK1.7,含注释) 立即下载

记录阅读Java 7 HashMap源码过程,Java 7 与 Java 8 两个版本的源码区别比较大,主要是Java 8 中引入了红黑树存储。本篇只对get()方法和put()方法进行解析。


分析两个方法前,先认识HashMap几个关键的成员变量

  • static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
    默认的初始化容量,1<<4=16,至于为什么是16而不是15,17后面讲解

  • static final int MAXIMUM_CAPACITY = 1 << 30;
    允许的最大容量值

  • static final float DEFAULT_LOAD_FACTOR = 0.75f;
    翻译为加载因子,与HashMap的扩容有关

  • transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
    HashMap中存放键值对的数组,我们所讲的容量指的就是table数组的大小,初始值指向一个空数组

  • transient int size;
    形象来说就是记录当前装了多少个桶(桶指的是table[i])

  • int threshold;
    阈值,HashMap扩容的关键,值为( 加载因子 * 容量 ),当size >= threshold且需要插入新的键值对时,HashMap执行扩容操作。

put()
public V put(K key, V value) {
    //第一次插入元素时,先对table进行初始化
    if (table == EMPTY_TABLE) {
        inflateTable(threshold);
    }
    //HashMap允许key值为null,存放在table[0]中
    if (key == null)
        return putForNullKey(value);
    //计算key的hash值
    int hash = hash(key);
    //获取hash值对应的下标
    int i = indexFor(hash, table.length);
    //遍历Entry链,如果hash相等并且key值相等,替换旧值并返回旧值
    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;
        }
    }
    //与HashMap的fail-fast机制有关,可以在某度查阅相关内容
    modCount++;
    //增加新的键值对
    addEntry(hash, key, value, i);
    return null;
}

接下来对相关方法分析:

//初始化table
private void inflateTable(int toSize) {
    //保证table数组容量大小为2^n,有兴趣的可以进入查看算法的实现
    int capacity = roundUpToPowerOf2(toSize);
    //初始化阈值大小,值系capacity*loadFactor
    threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
    //初始化table数组
    table = new Entry[capacity];
    //官方解释为初始化哈希掩码,不太了解,忽略
    initHashSeedAsNeeded(capacity);
}

之所以要保证table数组容量为2^n,是和解决hash冲突有关,后面涉及到再分析。
putForNullKey(value)方法遍历table[0]链,替换并返回旧值。

//获取键的hash值
final int hash(Object k) {
    int h = hashSeed;//hash掩码,忽略
    if (0 != h && k instanceof String) {
        return sun.misc.Hashing.stringHash32((String) k);
    }

    h ^= k.hashCode();//hashCode是一个native方法,用于获取hash值

    // 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);
}

//根据hash值获取数组下标
static int indexFor(int h, int length) {
    // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
    return h & (length-1);
}

indexFor(int h, int length)方法比较简单,将hash值与数组长度作相与操作,得出的值即为数组下标。在上面提及到,数组的容量大小为什么要保证是2^n?举个栗子看看:

//两个hash值分别为:1011,1010
//如果容量大小=15,数组下标0~14,用二进制表示为:1110,相与结果:
1011 & 1110 = 1010 = 10
1010 & 1110 = 1010 = 10

//如果容量大小=16,数组下标0~15,用二进制表示为:1111,相与结果:
1011 & 1111 = 1011 = 11
1010 & 1111 = 1010 = 10

可以看到:如果容量大小用二进制表示不是全1,即不为2^n,将会导致hash冲突更为频繁。但是,还有一个问题,从indexFor方法得到的是hash值低位与长度相与的结果,试想下,如果两个hash值高位不同而低位相同,得出的下标结果是一致的,hash冲突的概率还是比较高,为此,引入了hash(Object k)来解决这个问题。

在hash(Object k)方法中,官方给的解释翻译为:这个函数确保哈希码在每个位的倍数不变的情况下,有一定数量的碰撞,感觉比较抽象,网上资料解释为扰乱函数,通过一系列位运算,能够保证hash每一位的变化,都会改变最终得到的结果,这就解决了高位不同而低位相同导致冲突的问题,可以参考这篇文章

再来看看addEntry方法

/**
 * Adds a new entry with the specified key, value and hash code to
 * the specified bucket.  It is the responsibility of this
 * method to resize the table if appropriate.
 */
void addEntry(int hash, K key, V value, int bucketIndex) {
    if ((size >= threshold) && (null != table[bucketIndex])) {
        //每次扩容两倍,保证容量大小为2^n
        resize(2 * table.length);
        //扩容后重新计算hash值和桶下标
        hash = (null != key) ? hash(key) : 0;
        bucketIndex = indexFor(hash, table.length);
    }

    createEntry(hash, key, value, bucketIndex);
}

void createEntry(int hash, K key, V value, int bucketIndex) {
    Entry<K,V> e = table[bucketIndex];
    //新的entry将从头部开始插入到entry链中
    table[bucketIndex] = new Entry<>(hash, key, value, e);

    size++;
}

为指定的key,value,hashcode添加新的entry到指定的桶中(index[i]),addEntry方法需要处理扩容问题。逻辑比较好理解,如果达到阈值(threshold)且指定的桶不为空,则进行扩容。看看resize方法:

void resize(int newCapacity) {
    Entry[] oldTable = table;
    int oldCapacity = oldTable.length;
    //如果达到最大允许的容量,停止扩容
    if (oldCapacity == MAXIMUM_CAPACITY) {
        threshold = Integer.MAX_VALUE;
        return;
    }

    Entry[] newTable = new Entry[newCapacity];
    //重构新的table
    transfer(newTable, initHashSeedAsNeeded(newCapacity));
    table = newTable;
    //更新阈值
    threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}

transfer方法将会遍历每个entry,重新计算下标并插入到新的table中,可想而知,resize的成本非常大,所以必须科学地设定初始容量、阈值,和选择合适的散列算法,降低resize频率。

get()

get方法就相对easy多了,源码:

public V get(Object key) {
    //若key为null,从table[0]中遍历
    if (key == null)
        return getForNullKey();
    Entry<K,V> entry = getEntry(key);

    return null == entry ? null : entry.getValue();
}
/**
 * Returns the entry associated with the specified key in the
 * HashMap.  Returns null if the HashMap contains no mapping
 * for the key.
 */
final Entry<K,V> getEntry(Object key) {
    //每个桶都是空的,返回null
    if (size == 0) {
        return null;
    }
    //计算hash值
    int hash = (key == null) ? 0 : hash(key);
    //遍历指定桶中的entry链
    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 != null && key.equals(k))))
            return e;
    }
    return null;
}

官方解释得很清楚,从HashMap中返回指定key的entry,如果如果不存在key的映射,返回null。

java7hashmap源码-JAVA-:JAVA- java7 hashmap源码 Notes 原理 basic 1 数据结构中各种东西的数量很很重要!!!可以考虑在在数据结构中定义一下 2 Java hashtable的contains用来查找是否存在value,和containsValue类似 查找key使用containskey方法, 3 hashtable查询的的时间复杂度为O(1)可以使用put和get方法存储查询数据。List类使用add和get。 4 new HashMap<String>>(); 定义的这个数据结构中,如果每次都hashMap.put(string, new hashtable<>)的话会覆盖掉之前的hashtable,所以最好先定义hashtable,存储完成后再放入map中,或者hashtable先get 出value再put进入新value。 5 new HashMap<String>>() private class Tuple { private int DID; private int position; public 立即下载

相关推荐

java7hashmap源码-Excellent-Blog-share:欢迎分享优秀博客

java7 hashmap源码 Excellent-Blog-share Welcome to share excellent blogs . 当你的能力还驾驭不了你的目标时,就应该沉下心来历练 当你的才华还撑不起你的野心时,那你就应该静下心来学习 #目录 ###附录 java系列 java8 jvm java并发 java集合相关 Others DesignPatterns系列 Dubbo系列 Zookeeper系列 Redis系列 - [伯乐在线——Redis]() MQ系列 Database系列 - [MySQL索引和SQL调优]() - [揪出MySQL延迟上千秒的元凶]() - [掌握MySQL数据库这些优化技巧,事半功倍!]() Netty系列 - [Java NIO之缓冲]() - [Java NIO之选择器]() - [Java NIO之通道]() - [Netty源码分析目录]() Spring 系列 Spring Boot系列 Spring Cloud系列 微服务系列 Excellent-Blogs Excellent-Githubs ###企业 ###个人

Java 7、8 HashMap源码详解与分析

核心就是:基于哈希值的桶和链表。一般就是用数组来实现桶发生碰撞的时候,用链表来链接发生碰撞的元素假设我们, 对下面所有元素进行hash并放入到hash表中。O(1)的平均查找、插入、删除时间.致命缺点是哈希值的碰撞(collision哈希碰撞:元素通过哈希函数计算后,会被映射到同一个桶中。上面的26, 126就发生了哈希碰撞。

写写平时的技术与感想 2918

java7hashmap源码-network_program:学习java网络编程

java7 hashmap源码 [toc] java网络编程学习 简介 用于存放学习java网络编程过程遇见的重难点笔记和相关代码 附带代码大部分是《java网络编程 第四版》的课程代码 对运算字符串进行识别的作业 @since2020.11.26 IO流 - 多线程 @since2020.11.26 internet地址 @since2020.11.27 URL 和 URI 类 @since2020.11.28 HTTP @since 2020.11.28 URLConnection @since 2020.11.29 Socket ServerSocket 学习 @since 2020.12.01 非阻塞I/O @since 2020.12.01 IO Stream read() 和 write() public abstract int read(int) throws IOException public abstract void write(int) throws IOException 这两个抽象方法是由 inputStream 和 outputStream 的具体子类实

HashMap-JDK7源码详解

1、HashMap是散列表的一种,HashMap本身采用数组来进行储存。同时HashMap采用拉链法来解决hash冲突,拉链法就是通过链表来解决hash冲突。所以说整体上来看,HashMap采用的数据结构=数组(主)+单链表(副)大致是这样的一个结构每个链表就算哈希表的桶(bucket)链表的节点值就算一个键值对构造函数源码先贴一下,后面参数介绍会使用到。init();}下面的代码有些顺序和源码可能不太一样,仅仅是顺序,笔者是为了更好的阅读体验/*名词介绍。...

youthlql的博客 1716

在Java8与Java7中HashMap源码实现的对比

主要介绍了在Java8与Java7中HashMap源码实现的对比,内容包括HashMap 的原理简单介绍、结合源码在Java7中是如何解决hash冲突的以及优缺点,结合源码以及在Java8中如何解决hash冲突,balance tree相关源码介绍,需要的朋友可以参考借鉴。

高效静音黑科技 —— 单相直流无刷电机驱动器

然而,传统的BLDC电机驱动通常依赖于三相架构,电路复杂,成本高昂,且在低功率应用中显得有些“大材小用”。单相直流无刷电机驱动器作为一项高效、静音、经济的技术,正逐渐改变着各个领域的电机驱动方式。其精巧的控制策略、显著的优势以及广阔的应用前景,都预示着这项技术将在未来扮演越来越重要的角色。它相较于传统的三相驱动,显著简化了电路结构,降低了成本,尤其适用于低功率、对静音要求极高的应用场景。通过这些模块的协同工作,单相直流无刷电机驱动器能够实现对电机速度、扭矩的精确控制,并最大程度地降低噪声和振动。

wen8789的博客 1763

Carson带你学Java:手把手带你源码分析 HashMap 1.7

前言 HashMap 在 Java 和 Android 开发中非常常见 今天,我将带来HashMap 的全部源码分析,希望你们会喜欢。 本文基于版本 JDK 1.7,即 Java 7 关于版本 JDK 1.8,即 Java 8,具体请看文章Java源码分析:关于 HashMap 1.8 的重大更新 目录 1. 简介 类定...

Carson带你学Android 4万+

【小白教程】本地部署VLM-R1模型(使用Docker)

通过Docker本地部署VLM-R1大模型,详细教程。

m0_69855053的博客 2937

Jdk7HashMap源码分析

一、HashMap的成员变量   int DEFAULT_INITIAL_CAPACITY = 16:默认的初始容量为16   int MAXIMUM_CAPACITY = 1 &amp;lt;&amp;lt; 30:最大的容量为 2 ^ 30   float DEFAULT_LOAD_FACTOR = 0.75f:默认的加载因子为 0.75f   Entry&amp;lt; K,V&amp;gt;[] table...

小白 936

RT-DETR改进策略【卷积层】| ECCV-2024 小波卷积WTConv 增大感受野,降低参数量计算量,独家创新助力涨点

本文记录的是利用模块优化的目标检测网络模型。的目的是在不出现过参数化的情况下有效地增加卷积的感受野,从而解决了在感受野扩展中的参数膨胀问题。本文将其加入到深度可分离卷积中,有效降低模型参数量和计算量,并二次创新,使模块更好地捕捉低频特征,增强网络性能。Wavelet Convolutions for Large Receptive Fields小波卷积及其改进的实现代码如下: 四、创新模块 4.1 改进点1⭐ 模块改进方法:加入(第五节讲解添加步骤)。添加后如下:模块改进方法:基于的(第五节讲解添加步骤)

Limiiiing的博客 1503

Auto.js实现视频号点赞自动化

摘要:本文介绍了一个微信视频号自动化点赞的实现方案。通过定位点赞图标和数量容器,点击点赞按钮后检测点赞数变化,若发现取消点赞则自动补点。核心代码包括:1)获取点赞容器和图标;2)记录点赞前后数量;3)判断是否误取消并补点;4)循环执行点赞和滑动页面操作。该方案解决了滑动页面可能导致误取消点赞的问题,实现了自动化批量点赞功能。文章强调仅供学习参考,提醒勿滥用该技术。

分享前端工程化、AI 应用、Agent 开发与大模型实践! 2574

HashMap源码分析 jdk7

jdk 1.7 java.util.HashMap 类图 通过IDEA生成HashMap类图。HashMap实现了Map接口。 状态 AbstractMap // Views /** * Each of these fields are initialized to contain an instance of the * appropriate view the first time this view is requested. The views are

weixin_43511928的博客 202

【推荐100个unity插件之7】使用BehaviorDesigner插件制作BOSS的AI行为树

Behavior Designer是一个行为树插件,是一款为了让策划,程序员,美术人员方便使用的可视化编辑器。Behavior Designer提供了强大的AP1可以让你轻松的创建tasks(任务),配合uScript和PlayMaker这样的插件,可以不费吹灰之力就能够创建出强大的Al系统,而无需写行代码。(不懂PlayMaker的,我后面在单独出文章介绍一下,可以期待一下)

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 6565

​hashmap源码解析(Java7、Java8)

集合工具类使用线程1.hashmap源码解析(Java7)01.重要变量staticfinalintDEFAULT_INITIAL_CAPACITY=16; //默认初始容量,必须是2的n次方 staticfinalintMAXIMUM_CAPACITY=1<<30; //最大容量,当通过构造方法传入的容量比它还大时,就用...

weixin_33782386的博客 90

Cesium.Ray 知识详解,示例代码

Cesium.Ray 是 CesiumJS 中用于表示三维空间中无限射线的核心类,广泛应用于地理信息系统(GIS)、三维可视化和碰撞检测等场景。射线由起点(origin)和方向向量(direction)定义,数学表达式为 ( P(t) = \text{origin} + t \times \text{direction} )。核心属性包括起点和方向向量,常用方法包括射线与平面的交点计算、根据距离获取射线上的点等。在 Cesium 中,Cesium.Ray 常用于地形碰撞检测、鼠标点选对象和雷达探测模拟等场景

大剑师兰特的GIS世界 424

Ambari 安装部署教程(手把手教学)【超级详细】

本文为读者提供了一套超详细的 Apache Ambari 安装部署教程,采用手把手教学方式,适合初学者及大数据运维人员。内容涵盖前期准备、环境配置、Ambari Server 与 Agent 安装、集群初始化配置、常见问题排查等全流程操作,确保用户能够顺利搭建稳定的 Hadoop 大数据平台管理系统。

Five的博客 1万+

java1.7HashMap源码解析

类图 使用数组加链表实现,HashMap中每对(key,value)被封装成一个Entry对象(HashMap的静态内部类)。 static class Entry<K,V> implements Map.Entry<K,V> { final K key; V value; Entry<K,V> next; int hash; /** * Creates new entry. */ .

wangyajun0002的博客 969

人工智能训练师三级考试大纲深度解读|理论+实操分值分布+六大模块占比

三级人工智能训练师考试分为理论和实操两大模块(各100分,合格线60分)。理论考试包含AI基础(30%)、数据标注(25%)、模型训练(20%)、测试(15%)和系统运维(10%),题型为客观题;实操考核侧重数据标注(40%)、模型测试(35%)和系统运维(25%),采用现场操作形式。复习应优先关注AI基础和数据标注等高分值模块,实操需重点掌握标准流程和结果准确性(占评分70%)。考试要求两模块均达标,理论侧重概念理解,实操强调规范执行与文档完整。

白话机器学习 1084

Java 7中HashMap源码解析

package java.util;   import java.io.*;      public class HashMap<K,V>       extends AbstractMap<K,V>       implements Map<K,V>, Cloneable, Serializable   {          // 系统默认初始容量,必须是2的n次幂,这是出于优化考虑的

qq_33387902的博客 356

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

一篇文章搞清楚java7/java8的HashMap、ConcurrentHashMap

本文篇幅较长建议阅读顺序 1、Java7 HashMap 2、Java8 HashMap 3、Java7 ConcurrentHashMap 4、Java8 ConcurrentHashMap 那既然需要切换jdk,那大家根据自己的情况选择阅读,互相之间我会尽量写的独立,不影响阅读,废话不多说,开始吧! 一、Java7 HashMap java 7的HashMap相较于另外我要讲的三个应该是最简单...

paul、的博客 394

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

JDK1.7HashMap源码解析

HashMap已经看了很多篇文章了,今天还是自己解析一遍吧。 我先大致介绍下HashMap的内部结构再跟着源码解读一番 众所周知HashMap的内部就是一个哈希表 什么是哈希表? 如果我们利用数组可随机访问的特性,将要存入的键通过一种哈希算法转换成一个数字,并把这个数字转换成数组的下标,然后将键和他对应value放入数组中。那么我们再通过这个键查找时,只需要继续利用这个算法,那么我们就只需要用O...

wmh1152151276的博客 402

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Java集合框架--HashMap源码解析(JDK1.7)

HashMap是一种定义HashMap是Java Collection Framework的重要一员。它实现了Map接口,继承AbstractMap。

Monkey__z的博客 376

【Java集合】HashMap(1.7)源码解析&线程安全问题

本文基于JDK 1.7,认识HashMap。 一、HashMap起步 1. 数据结构 HashMap是一个基于哈希表的 Map 接口的实现,以 key-value 的形式存储数据,从而达到高效地存储与获取数据元素。在 Java 中,HashMap 实现了 Map 接口,继承了 AbstractMap 抽象类: public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K.

周二Show 459

Java7/8中的 HashMap 和 ConcurrentHashMap 全解析

文章目录Java7 HashMapput 过程分析数组初始化计算具体数组位置添加节点到链表中数组扩容get 过程分析Java7 ConcurrentHashMap初始化put 过程分析初始化槽: ensureSegment获取写入锁: scanAndLockForPut扩容: rehashget 过程分析并发问题分析Java8 HashMapput 过程分析数组扩容get 过程分析Java8 Co...

lzw2016的博客 315

HashMap1.7部分源码解析

文章目录HashMap1.7部分源码讲解put HashMap1.7部分源码讲解 put public V put(K key, V value) { if (table == EMPTY_TABLE) { // 初始化数组 inflateTable(threshold); } if (key == null) return putForNullKey(value); // 通过

thesummers的博客 176

java集合-Map HashMap 源码解析

HashMap是基于哈希表实现的,每一个元素是一个key-value对,无序,不可重复。HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap。HashMap 实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆。

loushaoqi的博客 877
上一篇: AES加解密例子
下一篇: 简单分析Class类文件
HamalAlpha
博客等级 码龄11年 5粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值