参考自https://blog.csdn.net/mbshqqb/article/details/79799009
了解HashMap前,先了解一下Java集合。
一、Java集合
Java集合是一个用来存储对象的容器,Java集合类存放于 java.util 包中。
集合有以下特征:
1、集合只能存放对象。比如你存一个 int 型数据 1放入集合中,其实它是自动转换成 Integer 类后存入的,Java中每一种基本类型都有对应的引用类型。
2、集合存放的是多个对象的引用,对象本身还是放在堆内存中。
3、集合可以存放不同类型,不限数量的数据类型。
集合类型主要有3种:set(集)、list(列表)和map(映射)。
集合接口分为:Collection和Map, list、set实现了Collection接口,HashMap实现了Map接口。
二、HashMap
1、什么是HashMap
HashMap是基于哈希表,实现了Map接口,非线程安全的,属于map类型集合,即键值对这种模式。
2、HashMap的原理
HashMap是基于哈希表(散列表)的Map接口的实现。HashMap储存的是键值对,这个键值对也叫做Entry,而每个Entry都是存储在数组当中,因此这个数组就是HashMap的主干。HashMap数组中的每一个元素的初始值都是NULL。hashmap中的链表是用来解决hash冲突的,而hashmap解决hash冲突的办法采用的是“链地址法”
HashMap的特点
底层数据结构是数组和链表来相结合的数据结构。属于hash表(散列表)的一种
HashMap 是允许使用null键和null值的(key为空的时候设置的默认的hash值为0,存储在数组的第一个位置)
HashMap是数组与链表结合的散列集合,因此hashmap很快。
此类不保证映射的顺序,特别是它不保证该顺序恒久不变
数组:存储区间连续,占用内存严重,寻址容易,插入删除困难;
链表:存储区间离散,占用内存比较宽松,寻址困难,插入删除容易;
HashMap的实现原理
HashMap通过put,get方法来存取数据。
HashMap的put()原理
HashMap通过put()添加数据,首先通过键对象的hash值来确定加入的entry对象的位置,如果发生了Hash冲突,就通过链表插入新的entry对象,采用的是头插入方式。添加数据的关键方法如下:
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) //--entry数组当前位置为空,直接赋值
tab[i] = newNode(hash, key, value, null);
else { //---entry数组当前位置不为空
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k)))) //---当前位置数组的元素key和hash都相等,直接覆盖
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