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 ...
随机推荐
- Django---forms表单使用(2)
Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试牛刀 1.创建Form类 from dja ...
- z-tree 回显所有选中的id
//回显选择的checkbox函数 function treeHxIdFun(obj) { var objTree = $.fn.zTree.init($("#demo"), se ...
- Echarts地图使用经验-地图变形和添加数据
关于echart2,echart3地图的使用一点人生经验: 1.echart3,echart2加载地图变形修复. 最近在使用echart2使用过程中,发现加载海南地图会产生变形.如下图,海南地图产生了 ...
- 关于ArcMap中打开ArcToolbox导致闪退的解决办法
最近好久不用ArcGis的小编要用到ArcMap去发送一个GP服务,发现按照套路打开ArcMap点击ArcToolbox时,发生了ArcMap的闪退现象,几经周折终于解决了问题. 希望也遇到这类问题的 ...
- 缓存ABC
缓存ABC Intro 缓存是一种比较常见的用来将提高系统性能的方式.从线程缓存.进程缓存.到内存缓存再到分布式缓存再到CDN,都是属于缓存的范畴. 缓存的本质是空间换时间以提高读的效率,牺牲一些内存 ...
- VS根据数据库生成实体类
一.在类库项目上添加新项 二. 三.依次填入数据库连接 选择数据库 就可以生成数据库实体
- java8 快速实现List转map 、分组、过滤等操作
利用java8新特性,可以用简洁高效的代码来实现一些数据处理. 定义1个Apple对象: public class Apple { private Integer id; private String ...
- 树莓派Ubuntu 16.04 MATA系统 修改用户文件夹名后,提示configure it with blueman-service
自从修改了树莓派的Ubuntu 16.04 MATA 系统的 /home/ 下的用户文件夹名后,使用vncserver远程操作,看到桌面每次都提示 Configured directory for i ...
- 码农人生——从未学过Android如何开发Android App 案例讲解-第002期案例
标题有点晃眼,本次分享是002期博文的实践故事,不会有任何代码.也不会教别人android 如何开发,类似博文已经有大批大批,而且还会有陆陆续续的人写,我写的文章,主要是经验之谈,希望总结出的一些方法 ...
- Linux systemtap定位系统IO资源使用情况(ok)
一.systemtap介绍 SystemTap是一个强大的调试工具,是监控和跟踪运行中的Linux 内核的操作的动态方法,确切的说应该是一门调试语言,因为它有自己的语法,也有解析.编译.运行等过程(准 ...