hashMap的源码实现
1、初步认识hashMap
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>(5);
map.put("中国", 1);
map.put("美国", 2);
map.put("俄罗斯", 3);
map.put("英国", 4);
map.put("法国", 5);
for(Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
debug模式,从数据结构上认知HashMap:

JDK8中HashMap的数据结构源码:
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
2、HashMap的两个重要参数
/**
* The default initial capacity - MUST be a power of two.
* table的默认初始容量
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* The load factor used when none specified in constructor.(负载因子)
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
- capacity 就是初始化HashMap时的数组容量,load factor 指负载因子;
- 当我们对迭代性能要求比较高时,不能把capacity设置的太大;同时load factor不要超过0.75,否则会明显增加冲突几率,降低HashMap性能;
- hashMap中元素数量( put 的元素个数) > (负载因子 * 容量) 时,就需要扩容为原来的2倍。
3、HashMap的put(Key k,Value v)的原理
数据存储的步骤:
- 当在第一次put时,先对table初始化,通过hash计算得到存放位置table[i],存放。
- 当再次put时,同样经过hash计算得到位置,则采用链表法解决冲突,存放在相同位置的next区域。
- 在JDK8中设置了链表的默认阈值为8,如果超过这个值,则进行树化。
- 如果节点已经存在就替换old value(保证key的唯一性)。
- 如果bucket满了(超过load factor*current capacity),就要resize,变为原来2倍。
面试题:解释HashMap的原理,数据量增大时,数据结构是什么样的?
在数据量小的时候,HashMap是按照链表的模式存储的。当数据量变大之后,为了进行快速的查找,会将这个链表变成红黑树(均衡二叉树),用hash码作为数据的定位来进行保存。
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
} /**
* Implements Map.put and related methods
*
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent if true, don't change existing value
* @param evict if false, the table is in creation mode.
* @return previous value, or null if none
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
hashMap的源码实现的更多相关文章
- HashMap的源码分析
hashMap的底层实现是 数组+链表 的数据结构,数组是一个Entry<K,V>[] 的键值对对象数组,在数组的每个索引上存储的是包含Entry的节点对象,每个Entry对象是一个单链表 ...
- HashMap的源码学习以及性能分析
HashMap的源码学习以及性能分析 一).Map接口的实现类 HashTable.HashMap.LinkedHashMap.TreeMap 二).HashMap和HashTable的区别 1).H ...
- HashMap的源码分析与实现 伸缩性角度看hashmap的不足
本文介绍 1.hashmap的概念 2.hashmap的源码分析 3.hashmap的手写实现 4.伸缩性角度看hashmap的不足 一.HashMap的概念 HashMap可以将其拆分为Hash散列 ...
- Java——HashMap底层源码分析
1.简介 HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的. HashMap 最多只允许一条记录的key为 nu ...
- Java中HashMap的源码分析
先来回顾一下Map类中常用实现类的区别: HashMap:底层实现是哈希表+链表,在JDK8中,当链表长度大于8时转换为红黑树,线程不安全,效率高,允许key或value为null HashTable ...
- java基础,集合,HashMap,源码解析
最怕,你以为你懂咯,其实你还不懂: 见贤思齐,看看那些我们习以为常的集合,通过相关定义.源码,思考分析,加深对其的理解,提高编码能力,能做一个略懂的程序员: 做几个我们常用的集合类.开篇HashMap ...
- 【JDK8】HashMap集合 源码阅读
JDK8的HashMap数据结构上复杂了很多,因此读取效率得以大大提升,关于源码中红黑树的增删改查,博主没有细读,会在下一篇博文中使用Java实现红黑树的增删改查. 下面是类的结构图: 代码(摘抄自J ...
- HashMap框架源码深入解读,面试不用愁
在Java Collections Framework的体系中中,主要有两个重要的接口,一个是List.Set和Queue所属的Collection,还有一个就是Map接口了.在上一篇文章中介绍了Li ...
- java jdk 中HashMap的源码解读
HashMap是我们在日常写代码时最常用到的一个数据结构,它为我们提供key-value形式的数据存储.同时,它的查询,插入效率都非常高. 在之前的排序算法总结里面里,我大致学习了HashMap的实现 ...
随机推荐
- [Luogu 3794]签到题IV
Description 题库链接 给定长度为 \(n\) 的序列 \(A\).求有多少子段 \([l,r]\) 满足 \[ \left(\gcd_{l\leq i\leq r}A_i\right) \ ...
- BZOJ 1034: [ZJOI2008]泡泡堂BNB 贪心+排序
比较神奇的贪心 有点类似于田忌赛马. 如果我方最弱强于对面最弱,则直接最弱pk最弱. 如果我方最强强于对面最强,那么直接最强间pk. 否则,试着用我方最弱 pk 对方最强,看是否能打成平手. code ...
- telegraf 学习一 基本安装
telegraf 是influxdata 开发的一个插件驱动的服务器代理,可以方便的用来收集以及报告系统的metrics 我使用mac 系统,测试安装使用了brew 安装 下载地址 说明官方也提供了m ...
- 前端微信小程序资讯类仿今日头条微信小程序
需求描述及交互分析设计思路和相关知识点新闻频道滑动效果设计首页新闻内容设计首页新闻详情页设计我的界面列表式导航设计系统设置二级界面设计 设计思路(1)设计底部标签导航,准备好底部标签导航的图标和建立相 ...
- mysql 转大写
当前表: mysql> select * from table1; +----------+------------+-----+ | name_new | transactor | pid | ...
- restframework之节流
基本思路(原生Django而言): 在django2.x中,若出现节流(访问频率控制)的需求,我们首先想到的是使用一个字典(dict类型)来存储所有IP地址的访问时间记录,这是针对于匿名用户(IP)而 ...
- 计算电脑所能表示的最大最小值(c++)
C++当中获得现在计算机上所能表示的各种类型(比如int,long int,short int,double,float等)最大最小有两种方法,一种是使用c++预先定义的宏,对于有些编译器可能需要包含 ...
- 稀疏矩阵的存储(c++)
0 0 0 0 0 0 0 3 0 0 0 0 0 ...
- EduSoho之插件开发(脚手架搭建)
本文主要参考官方文档,地址为:http://developer.edusoho.com/plugin/start.html 插件开发的目的,一方面为了更好的扩展,另外一方面为了更好的维护. 关于这方面 ...
- PhpStorm 头部注释、类注释和函数注释的设置(稍微完善点)
首先,PhpStorm中文件.类.函数等注释的设置在:setting->Editor->FIle and Code Template->Includes下设置即可,其中方法的默认是这 ...