一、HashMap概述
HashMap通过键值的方式存储数据,为非线程安全的类,键和值可以为null,键不能重复,继承了AbstractMap并实现了Map接口
二、源码分析(基于JDK1.7)
1. HashMap中的主要成员变量
DEFAULT_INITIAL_CAPACITY:静态整型常量,默认初始化的容量,其值为16(必须是2的指数倍)
MAXIMUM_CAPACITY:静态整型常量,表示最大容量为2的30次方。如果通过构造器传入的容量大于最大容量,会被此最大容量值替换
DEFAULT_LOAD_FACTOR:静态浮点型常量,表示默认的加载因子,其值为0.75f;如果在构造器中没有指定加载因子,则使用此默认值
table:存储数据的Entry数组(Entry<K,V>[]),会做必要的调整,长度是2的指数倍
size:HashMap的大小,是保存在HashMap里key-value键值对的数量
threshold:HashMap的阈值,用于判断是否要调整HashMap的容量,其值等于容量*加载因子
loadFactor:加载因子实际大小,常量
modCount:HashMap被改变的次数
2. HashMap中的读取(get方法)
2.1 如果传入的键(key)为null,则从Entry数组table中索引下标为0的链表中查找key为null的值并返回,未找到则返回null
2.2 如果传入的键(key)不为null,则获取key对应的哈希值hash
2.3 通过哈希值hash获取对应在table数组中的索引下标(h & (length-1))
2.4 循环遍历table数组中该索引下标对应的Entry链表
2.5 如果传入的键(key)的哈希值(hash)等于该Entry的哈希值(hash),
并且传入的键(key)等于(==)或等同于(equals)该Entry的key,
则此Entry便是要查找的Entry对象,遍历完该Entry链表如果还未查找到,则返回null
2.6 返回查找到的Entry对象的值(value),未查找到则返回null
3. HashMap中存入键值(put方法)
3.1 如果key为null,则从Entry数组table中索引下标为0的链表中,
查找是否已经存在了key为null的Entry,如果存在则替换这个Entry的值为新的值,并返回旧值;
如果不存在key为null的Entry,则先把修改数(modCount)自增1,然后添加一个新的Entry,
key为null,value为传入的值,并把该Entry放入table[0]位置上链表的头部,并返回null。
3.2 如果key不为null,先获取key的哈希值hash,并通过hash确定Entry数组table的索引下标i
对table[i]位置的链表进行循环遍历,查找是否已经存在key值相同的Entry(传入key的哈希值
与该Entry的哈希值相等,并且传入key等于或等同于Entry的key),如果存在则把它的值替换
成新值,并返回旧值;
如果不存在,则先把修改数(modCount)自增1,然后在table[i]对应的链表的头部添加一个Entry
并返回null。
三、要点分析
1. 链表的原理和实现
HashMap中的链表由Entry类组成,Entry包含三个元素:key,value和next(指向下一个Entry的)
在HashMap中的链表加入新的Entry,会放在链表头部位置,新的Entry的next元素指向原来在链表头部的Entry
2. modCount的作用
modCount为修改次数,在进行put、remove、clear等操作时会修改数modCount加1
HashMap中不是线程安全的,如果在使用迭代器的过程中有其他线程修改了HashMap,那么将抛出ConcurrentModificationException,即Fail-Fast策略
在迭代过程中,是通过modCount跟expectedModCount是否相等来判定其他线程有没有修改的,如果不相等,说明其他线程修改了
四、总结
1. HashMap是基于哈希表的Map接口的非同步实现,允许key和vaue为null
2. HashMap内部是有数组和链表实现的,通过key的哈希值找到在数组中位置,
并遍历该位置的链表,找到key值相同的Entry。
3. 当我们往hashmap中put元素的时候,先根据key的hash值得到这个元素在数组中的位置(即下标),
然后就可以把这个元素放到对应的位置中了。如果这个元素所在的位子上已经存放有其他元素了,
那么在同一个位子上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。
从hashmap中get元素时,首先计算key的hashcode,找到数组中对应位置的某一元素,
然后通过key的equals方法在对应位置的链表中找到需要的元素。从这里我们可以想象得到,
如果每个位置上的链表只有一个元素,那么hashmap的get效率将是最高的
相关推荐
在深入探讨HashMap的实现原理之前,我们需要了解两个关键的接口方法:`hashCode()`和`equals()`。 根据《Effective JAVA》的建议,当重写`equals()`方法时,也应重写`hashCode()`方法。这是因为在HashMap中,`...
HashMap 的核心原理是将键(key)通过哈希函数转化为数组索引,然后将键值对(key-value pair)存储在数组的对应位置。如果多个键经过哈希计算得到相同的索引,HashMap 利用链表处理这种哈希冲突,形成链式存储。 ...
面试中,HashMap的源码分析与实现是一个常见的考察点,因为它涉及到数据结构、并发处理和性能优化等多个核心领域。本篇文章将深入探讨HashMap的内部工作原理、关键特性以及其在实际应用中的考量因素。 HashMap基于...
### HashMap的实现原理 #### 1. HashMap概述 HashMap 是 Java 集合框架中一个非常重要的类,它实现了 Map 接口,并提供了基于哈希表的存储方式。与其它 Map 实现不同的是,HashMap 允许使用 `null` 键和 `null` 值...
《HashMap 源码解析——JDK11版本》 HashMap是Java中广泛使用的非同步散列表,其设计和实现是高效且灵活的。在JDK1.8之前,HashMap的底层数据结构采用的是数组+链表的方式,这种方式称为“拉链法”来解决哈希冲突。...
本文将深入探讨如何使用HashMap来构建一个电话本管理系统,并通过源码分析增强理解。 HashMap是Java集合框架中的一个核心类,它实现了Map接口。Map接口存储键值对(key-value pairs),而HashMap则使用哈希表数据...
5. 源码分析: 查看`HashTable`和`HashMap`的源码,可以发现两者在内部实现上也有所不同。`HashTable`直接使用了数组+链表的方式,而`HashMap`在Java 8及以后版本引入了红黑树优化,当链表长度达到一定阈值(8)时...
本文将深入解析Java 1.8中HashMap的put方法源码,探讨其内部工作原理。 首先,我们了解HashMap的基本结构。在Java 1.8中,HashMap由数组加链表或红黑树构成。初始容量为16,这是通过`DEFAULT_INITIAL_CAPACITY`常量...
通过分析和学习易语言HashMap类的源码,开发者可以深入理解哈希表的工作原理,以及易语言如何实现高效的数据结构。这对于提升编程技能,尤其是理解和优化数据结构的性能,具有很大的帮助。同时,源码也可以作为参考...
"学习笔记:三数组实现的HashMap"这篇博客文章可能讨论了一种非标准但有趣的HashMap实现,使用了三个数组来代替标准的哈希表结构。这里我们将深入探讨这种三数组实现HashMap的原理和可能的优势。 1. **基本概念**:...
HashMap类在Java编程...在阅读《HashMap1.js》和《HashMap.js》这两个文件时,可以深入分析其JavaScript版本的HashMap实现,虽然与Java版本可能有所不同,但基本的哈希映射原理是相通的,有助于拓宽对哈希表的理解。
#### 二、HashMap线程安全问题分析 在多线程环境中,`HashMap`的主要线程安全问题包括但不限于: 1. **链表死循环问题**:在JDK 1.7中,当多个线程同时进行`put`操作时,可能会出现链表死循环的情况,这是一个严重...
Java集合系列之HashMap源码分析 Java集合系列之HashMap源码分析是Java集合系列中的一篇非常重要的...HashMap源码分析是非常重要的,它能够帮助我们更好地理解HashMap的内部机制和实现原理,从而更好地使用HashMap。
在面试过程中,尤其是2020年及以后的技术面试中,深入理解HashMap的实现原理成为了考察候选人基础技能的重要环节。本篇文章将通过分析一个名为"MyHashMap"的手写HashMap源码,来探讨HashMap的内部机制,帮助提升编程...
这些数据结构在Android应用中广泛使用,理解它们的底层实现原理和性能特性,能够帮助开发者选择最适合的数据结构来存储和处理数据,从而提高程序的运行效率。 开源分析部分则强调了社区力量在Android开发中的作用。...
通过分析源码,开发者可以深入理解哈希表的工作原理,学习如何在易语言中实现高效的数据结构,这对于提升程序性能和优化内存管理至关重要。同时,这也为自定义数据结构或实现其他哈希表相关的功能提供了基础。