学习笔记——HashMap的底层结构及相关知识
HashMap底层是由数组和链表组成的,它的原理是根据key的hashcode再散列取其hash值,然后通过这个hash值与table长度得到key对应的value应该存在数组的哪个位置,其结构如下图
我们在看下HashMap实现put和get的代码以及新建一个HashMap的代码
HashMap有几个默认参数,DEFAULT_INITIAL_CAPACITY是默认初始容量,值为16,MAXIMUM_CAPACITY为最大容量,值为2^30
DEFAULT_LOAD_FACTOR为默认加载因子,值为0.75
HashMap主要的几个成员变量有数组table,大小size,加载因子loadFactor,操作次数modCount,大小临界值threshold
通常我们新建一个HashMap都是用的new HashMap()这个构造方法,那我们就看一下在HashMap里面具体是怎么初始化的
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;//取默认加载因子作为新建的HashMap的加载因子
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);//默认初始容量乘以加载因子得出临界值
table = new Entry[DEFAULT_INITIAL_CAPACITY];//新建一个长度为16的数组
init();//源代码中该方法无具体实现
}
下面我们看一下我们常用的put(key,value)方法的实现(自己写的,整体思路和源代码一致,可能会有一些小的问题)
public V put(K key,V value){
if(key==null){
return putvaluefornul(value);//HashMap中,put的时候,如果key是null,一定是存放在table[0]所在的链表中
}
int hash = hash(key.hashcode());//对key的hashcode再散列,得到在数组中坐标对应的hash
int i = indexFor(hash,table.length);//根据key得到的hash和数组长度得到该key对应的数组下标
for(Entry e = table[i];e!=null;e = e.next){
if((e.hash==hash)&&(e.key==key||e.key.equals(key))){//根据hash和key比较看该key是否已存在
Object old = e.value;
e.value = value;//如果该key存在,则替换value
return old;
}
}
addEntry(hash,key,value,i);//不存在的时候增加
return null;
}
public V putvaluefornul(V value){
for(Entry e = table[0];e!=null;e=e.next){
if(e.key==null){
Object old = e.value;
e.value = value;//如果该key存在,则替换value
return old;
}
}
addEntry(0,null,value,0);//不存在的时候增加
return null;
}
public addEntry(int hash,K key, V value, int index){
Entry e = table[index];
e = new Entry(hash,key,value,e);//Entry的构造方法(int hash,K key,V value,Entry next)
if(size++>=threshold){
.....//这一块是扩大数组容量,通常是扩大0.5倍加1,扩容并不是单纯的扩大数组长度,元素的位置也都变了
}
}
我们再看一下get方法的实现
public V get(K key){
if(key==null){
return getvaluefornull(key);//如果key是null,则去table[0]中查找
}
int hash = hash(key.hashcode());//对key的hashcode再散列,得到在数组中坐标对应的hash
int i = indexFor(hash,table.length);//根据key得到的hash和数组长度得到该key对应的数组下标
for(Entry e = table[i];e!=null;e = e.next){
if((e.hash==hash)&&(e.key==key||e.key.equals(key))){//根据hash和key来查找value
return e.value;
}
}
return null;
}
public V getvaluefornull(K key){
for(Entry e = table[0];e!=null;e = e.next){
if(e.key==null){
return e.value;//根据key来查找对应的value
}
}
return null;
}
因为HashMap不是线程安全的,所以其中有modCount这个字段,可以用计HashMap被修改的次数来判断有几个线程修改了它。
- PE结构、SEH相关知识学习笔记
- PE结构、SEH相关知识学习笔记
- kettle菜鸟学习笔记1----相关准备知识
- 【鸟哥的linux私房菜-学习笔记】首次使用相关知识、在线求助 man page
- Java nio 学习笔记(一) Buffer(缓冲区)与Channel(通道)的相关知识
- Java容器学习笔记(二) Set接口及其实现类的相关知识总结
- PHP学习笔记(五)--基础知识之语言结构语句
- Struts2学习笔记01----初识struts2配置文件和相关基础知识
- 学习BMP相关知识的笔记
- UML学习笔记---了解UML,UML相关知识,相关概念
- VOLTE学习笔记(二)——IMS相关标识及SIP知识
- HashMap底层实现原理(学习笔记)
- 关于Scroller的学习及相关的知识笔记get
- 【C#学习笔记2】C#面向对象相关知识
- arm体系结构学习笔记 part2 -- 中断相关
- ARM底层学习笔记-中断体系结构
- 黑马程序员之SQL学习笔记: 数据库相关知识 小总结
- 端口相关知识学习笔记
- 大数据学习笔记之三十六 NewSQL相关知识