新手都能明白的hasMap底层实现原理
说到hasmap 先说说HasMap 和HasTable 的区别
相同点:都是用来存储键值对(key value),都实现了map接口的实现类
不同点:1, HasMap 的key,value,可以是null ,但是HasTable不可以
2:HasMap 是线程不安全的,效率高
HasTable是线程安全的。,效率低
存储方式 :用来存储键值
在jdk1.7之前,HasMap 是通过数组加上链表的结构方式来储存,在jdk1.8以后,HasMap 以数组 + 链表的+ 红黑树的方式存储。
数组:是一段连续固定的内存空间
链表:不要求内存是连续的 ;
当我查询的时候,需要遍历一次才能那到想要的值,查询效率低,数组只需要给定需要查询的数的索引就可以查询,效率高;
做添加或者删除的时候,数组需要移动内存。所以效率比较低,但是对于链表来说,直接将引用改变就可以.(也就是将他的指针指向前(后)一个,不会移动内存)
我们对HasMap的操作,无非是put()和get();
当我做的是put(key,value)操作的时候:
1,将k,v放到我的Node节点,
2,通过hascode(算法)得出具体的has值
3,将计算出来的has值做has运算后作为数组的下标,
---:通过下标存储,如果在当前的下标没有值的话,就直接把该node放在该位置,如果该下标是链表的方式,那么就将该node的key和该链表上node的key进行equals比较,如果结果所有返回的是flase,那么就将key放在该链表的末尾。如果其中有一个是true,那么传来的key对应的value将被覆盖。
当我需要get的时候:
同样的我需要get值的时候,我也会把key的值进行hascode()的方法拿到has值
,再将has值进行has算法,最终将返回的int做为下标,同过下标去获取到他的值,
如若在数组的该下标位置没有值的话,返回一个nulll,
如果将下标是一个单向链式结够,那么将传入的key值作和该链表的所有key进行equals,
返回的是false、那么就返回null,如果是true,那么就返回该位置的value。
loadFactor:负载因子: threshold
扩容原理
需要注意的是:HashMap使用的是懒加载
在我创建的时候,并不会主动去扩容,当首次调用put方法时,HashMap会发现table为空然后调用resize方法进行初始化,当添加完元素后,如果HashMap发现size(元素总数)大于threshold(阈值),则会调用resize方法进行扩容
大于threshold,if(threshold)不为空的话,就是table的初始化为阈值,否则默认为16;
负载因子默认为0.75 当我put value后,table的阈值增加到最大的时候。也就是等于负载因子最大负载的时候,就开始
进行扩容,扩容的长度为他的2倍。