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 ...
随机推荐
- Js与jQuery的相互转换
$()与jQuery() jQuery中$函数,根据传入参数的不同,进行不同的调用,实现不同的功能.返回的是jQuery对象 jQuery这个js库,除了$之外,还提供了另外一个函数:jQuery j ...
- SSM登陆拦截器实现
首先在springmvc中配置拦截器 <!-- 配置拦截器 --> <mvc:interceptors> <mvc:interceptor> <!-- 拦截所 ...
- iOS----------取数据的两种取法
NSMutableArray * dataArray =[responseDictionary valueForKeyPath:@"data.list_dic.list"]; NS ...
- Vue2.5笔记:Vue的实例与生命周期
理解与认识 Vue 的实例是我们学习 Vue 非常重要的一步,也是非常必须的,因为实例是它的一个起点,也是它的一个入口,只有我们创建一个 Vue 实例之后,我们才行利用它进行一些列的操作. 首先 Vu ...
- 20181112-PostgreSQL数据库dmp文件导入(记录一次数据导入)
20181112-PostgreSQL数据库dmp文件导入 标注:dmp文件导入,场景:多个schema导入 1. 环境准备: postgres集群master节点上,postgres用户执行以下操作 ...
- SQLServer之创建分布式事务
分布式事务创建注意事项 指定一个由 Transact-SQL 分布式事务处理协调器 (MS DTC) 管理的 Microsoft 分布式事务的起点. 执行 BEGIN DISTRIBUTED TRAN ...
- Linux常见系统故障
Linux常见系统故障 1.修复MBR扇区故障 2.修复GRUB引导故障 3./etc/inittab文件丢失 4.遗忘root用户密码 5.修复文件系统 6.磁盘资源耗尽故障 一.修复MBR扇区故障 ...
- 同步锁Synchronized与Lock的区别?
synchronized与Lock两者区别: 1:Lock是一个接口,而Synchronized是关键字. 2:Synchronized会自动释放锁,而Lock必须手动释放锁. 3:Lock可以让等待 ...
- 初学Django项目可能会遇到的问题
1. 出现莫名其妙的 app01 我项目中的app名字并不是app01,可是运行python manage.py makemigrations的时候总是提示app01不是已安装的app Applyin ...
- hashCode()方法对HashMap的性能影响
HashMap的put()方法会比较key的hash值,key的hash值获取方式如下: //HashMap的put方法 public V put(K key, V value) { return p ...