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 获取页面详情后 切换页面时 如何监听用户是否修改过信息
可以用 beforeRouteLeave 和 updated 来判断.export default { name: 'supplier', components:{cmtWrap,cmtContent ...
- 关于Keychain
1.Keychain 浅析 2.iOS的密码管理系统 Keychain的介绍和使用 3.iOS开发中,唯一标识的解决方案之keyChain+UUID
- 以太坊智能合约 Solidity 的常用数据类型介绍
目录 目录 1.数组 1.1.对数组的增删改查操作. 2.String.Bytes.Mapping的使用 3.Enums 和 Structs 的简单应用 4.Ether 单位和 Time 单位 5.A ...
- Windows Server 2012 NIC Teaming 网卡绑定介绍及注意事项
Windows Server 2012 NIC Teaming 网卡绑定介绍及注意事项 转载自:http://www.it165.net/os/html/201303/4799.html Window ...
- MySQL分数排名同分并列与不并列查询
Scores表 | Id | Score | | 3.50 | | 3.65 | | 4.00 | | 3.85 | | 4.00 | | 3.65 | 并列 | Score | Rank | | | ...
- 【原】Java学习笔记013 - 阶段测试
package cn.temptation; import java.util.Scanner; public class Sample01 { public static void main(Str ...
- c/c++ 多线程 多个线程等待同一个线程的一次性事件
多线程 多个线程等待一个线程的一次性事件 背景:从多个线程访问同一个std::future,也就是多个线程都在等待同一个线程的结果,这时怎么处理. 办法:由于std::future只能被调用一次get ...
- Web应用安全测试
偷偷挪用人家的分享: https://blog.csdn.net/aojie80/article/details/43836521 写的很棒 Burp Suite 介绍 https://blog.cs ...
- 虚拟机 与 host主机,无法ping通的问题
这个写的比较简单,先做以下记录 centos虚拟机安装到别的电脑上,因为linux中的程序需要向外有网络互通,所以需要重新设置ip 通过 ifconfig eth4 192.168.0.20 bro ...
- LeetCode算法题-Maximum Depth of N-ary Tree(Java实现)
这是悦乐书的第261次更新,第274篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第128题(顺位题号是559).给定n-ary树,找到它的最大深度.最大深度是从根节点到 ...