HashMap底层实现原理
HashMap底层实现
HashMap底层数据结构如下图,HashMap由“hash函数+数组+单链表”3个要素构成

通过写一个迷你版的HashMap来深刻理解
MyMap接口,定义一个接口,对外暴露快速存取的方法,并定义了一个内部接口Entry。
publicinterface MyMap<K,V> {
public V put(K k, V v);
public V get(K k);
publicinterface Entry<K, V>{
public K getKey();
public V getValue();
}
}
MyHashMap接口实现
publicclass MyHashMap<K, V> implementsMyMap<K, V> {
/*HashMap的要素之一就是数组,自然在这里,我们要定义数组,数组的初始化大小,还要考虑扩容的阀值*/
privatestaticintDEFAULT_INITIAL_CAPACITY = 1 << 4;
privatestaticfinalfloatDEFAULT_LOAD_FACTOR = 0.75f;
privateintdefaultInitSize = 1 << 2;
privatedoubledefaultLoadFactor;
private Entry<K, V>[] table;
privateintentryUserSize;
/*MyHashMap构造函数使用到了“门面模式”。这里的2个构造方法其实指向的是同一个,但是对外却暴露了2个“门面”!*/
public MyHashMap() {
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
public MyHashMap(intdefaultInitsize, doubledefaultLoadFactor) {
this.defaultInitSize = defaultInitsize;
this.defaultLoadFactor = defaultLoadFactor;
table = new Entry[this.defaultInitSize];
}
/*Put函数,根据Key计算出在Entry[]中的位置index,如果Entry[index]中的元素为null,那么可以放入其中,如果不为空,那么得遍历单链表,key相同时更新value,不相同时形成一个新的Entry“挤压”单链表。
put函数要考虑扩容和冲突问题,对于扩容:HashMap中的Entry的数量(数组以及单链表中的所有Entry)达到阀值,意味着新生成一个Entry数组并重新散列。关于冲突:利用位运算,让hash函数得到的数据散列开来,从而减低了碰撞的概率,当发生冲突时采用单链表解决冲突。*/
@Override
public V put(K k, V v) {
VoldValue = null;
if (entryUserSize > defaultInitSize * defaultLoadFactor) {
reSize();
}
intindex = hash(k) & (defaultInitSize - 1);
if (table[index] == null) {
table[index] = new Entry<K, V>(k, v, null);
entryUserSize++;
}else {
Entry<K,V> entry = table[index];
Entry<K,V> e = entry;
while (e != null) {
if (k == e.getKey() || k.equals(e.getKey())) {
oldValue = e.getValue();
e.value = v;
break;
}
e = e.next;
}
;
table[index] = new Entry<K, V>(k, v, entry);
entryUserSize++;
}
returnoldValue;
}
/*reSize函数,可以看出,对于HashMap而言,如果频繁进行resize操作,是会影响性能的,这个过程中数组变大,原来数组中的entry元素一个个的put到新数组的过程,需要注意的是一些状态变量的改变。*/
privatevoid reSize() {
List<Entry<K,V>> entryList = new ArrayList<Entry<K, V>>();
for (Entry<K, V> entry : table) {
while (entry != null) {
entryList.add(entry);
entry = entry.next;
}
}
if(entryList.size() > 0){
entryUserSize = 0;
defaultInitSize *= 2;
table = new Entry[defaultInitSize];
for(Entry<K,V> entry : entryList){
put(entry.getKey(),entry.getValue());
}
}
}
/*Has函数,要想散列均匀,就得对hash值进行二进制的位运算!*/
privateint hash(K k) {
inth = k.hashCode();
h ^= (h >>> 20) ^ (h >>> 12);
returnh ^ (h >>> 7) ^ (h >>> 4);
}
/*get函数,需要注意在遍历单链表过程中使用==或者equals来判断下即可。*/
@Override
public V get(K k) {
intindex = hash(k) & (defaultInitSize - 1);
Entry<K,V> entry = table[index];
if (entry == null) {
returnnull;
}
do {
if (k == entry.getKey() || k.equals(entry.getKey())) {
returnentry.getValue();
}
entry = entry.next;
}while (entry != null);
returnnull;
}
/*Entry接口实现*/
publicclass Entry<K, V> implements MyMap.Entry<K, V> {
private K key;
private V value;
private Entry<K, V> next;
public Entry() {
}
public Entry(K key, V value, Entry<K, V> next) {
this.key = key;
this.value = value;
this.next = next;
}
@Override
public K getKey() {
returnkey;
}
@Override
public V getValue() {
returnvalue;
}
}
}
单元测试
publicclass MyHashMapTest {
@Test
publicvoid test() {
MyMap<String,String> map = new MyHashMap<String, String>();
for(inti =0; i < 30; i++)
map.put("key" + i, "value" + i);
for(inti =0; i < 30; i++){
System.out.println("key" + i + ":" + map.get("key" + i));
}
}
}
测试结果
key0:value0 key1:value1 key2:value2 key3:value3
key4:value4 key5:value5 key6:value6 key7:value7
key8:value8 key9:value9 key10:value10 key11:value11
key12:value12 key13:value13 key14:value14 key15:value15
key16:value16 key17:value17 key18:value18 key19:value19
key20:value20 key21:value21 key22:value22 key23:value23
key24:value24 key25:value25 key26:value26 key27:value27
key28:value28 key29:value29
HashMap底层实现原理的更多相关文章
- HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别(转)
HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别 文章来源:http://www.cnblogs.com/beatIteWeNerverGiveU ...
- Java面试必问之Hashmap底层实现原理(JDK1.7)
1. 前言 Hashmap可以说是Java面试必问的,一般的面试题会问: Hashmap有哪些特性? Hashmap底层实现原理(get\put\resize) Hashmap怎么解决hash冲突? ...
- Java中HashMap底层实现原理(JDK1.8)源码分析
这几天学习了HashMap的底层实现,但是发现好几个版本的,代码不一,而且看了Android包的HashMap和JDK中的HashMap的也不是一样,原来他们没有指定JDK版本,很多文章都是旧版本JD ...
- HashMap底层实现原理(JDK1.8)源码分析
ref:https://blog.csdn.net/tuke_tuke/article/details/51588156 http://www.cnblogs.com/xiaolovewei/p/79 ...
- HashMap底层实现原理及面试常见问题
HashMap底层源码分析 1.HashMap底层采用的存储结构 1.在JDK1.7及之前采用的存储结构是数组+链表 2.到了JDK1.8之后采用的是数组+链表+红黑树 2.HashMap实现的原理 ...
- HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别
①HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算h ...
- (转)HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别
①HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算h ...
- HashMap底层实现原理以及HashMap与HashTable区别以及HashMap与HashSet区别
①HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算h ...
- HashMap底层实现原理及扩容机制
HashMap的数据结构:数组+链表+红黑树:Java7中的HashMap只由数组+链表构成:Java8引入了红黑树,提高了HashMap的性能:借鉴一张图来说明,原文:https://www.jia ...
随机推荐
- 使用vue-cli 初始化 vue 项目
1. 安装nodejs 2. 安装 vue-cli npm install -g vue-cli 安装前可以通过设置代理为淘宝仓库地址,以加快下载速度. npm config set registry ...
- Dynamics CRM Web API中的and和or组合的正确方式!
关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复243或者20170111可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...
- arcgis api 3.x for js 入门开发系列五地图态势标绘(附源码下载)
前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...
- Web项目发布后字体文件找不到
一.问题 ①ASP.NET项目,开发工具Visual Studio ②在IIS上发布之后,网页控制台报错,某某文件找不到,但是在服务器文件夹中看明明有那个文件 二.解决方法 ①>>打开II ...
- C#List<object>排序
//定义一个集合 var list = new List<Object>();//这里的Object为对象类型 //假设list已经有数据存进去,根据对象的某个字段升序或降序 var or ...
- python爬虫 | 一条高效的学习路径
数据是创造和决策的原材料,高质量的数据都价值不菲.而利用爬虫,我们可以获取大量的价值数据,经分析可以发挥巨大的价值,比如: 豆瓣.知乎:爬取优质答案,筛选出各话题下热门内容,探索用户的舆论导向. 淘宝 ...
- Linux Collection:网络配置
PAS 缺少ifconfig 安装相应软件[不推荐],尽量使用 ip 命令 sudo apt install gnome-nettool 补充,显示IP地址: ip show address PAS ...
- css3新特性合集
转自:https://www.cnblogs.com/xiaoxie2016/p/5964694.html (若原作者对此转载有疑问,联系删除,谢谢!) animation IE10 anima ...
- MySQL之视图、触发器、事务、存储过程、函数
一 视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,可以将该结果集当做表来使用. 使用视图我们可以把查询过程中的 ...
- web框架开发-快速认识Django中间件
中间件 中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出. 因为改变的是全局,所以需要谨慎实用,用不 ...