前面的博客中,我给大家分析过数组和链表两种线性表数据结构。数组存储区间连续,查找方便,但是插入和删除效率低下;链表存储区间离散,插入删除方便,但是查找困难。大家肯定会问,有没有一种结构,既能做到查找便捷,又能做到插入删除方便呢?答案就是我们今天要跟大家说的主角:哈希表。
我们先来看一下哈希表的百度定义
散列表(Hash table,也叫哈希表),是根据关键码值(Keyvalue)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash)函数。
下图是一个经典的哈希表实现方式图,来自百度百科。
再看一张图
这张图更明显的告诉我们哈希表采用的是一种“拉链法”实现的,关于拉链法,大家可以自行百度脑补。左边是数组,右边是链表,感觉十分像用数组把链表串起来,在一个长度为16的数组中,每个元素存储的是一个链表的头结点。接下来我们一起来分析一下HashMap的源码实现。
HashMap的继承关系
通过HashMap的继承关系,我们可以得知HashMap继承自抽象类AbstractMap,该Map又实现了Map接口,我们下来看一下Map接口包含哪些方法。
可以看出包含了我们常用的HashMap中的一些方法,接着我们来看HashMap的父类AbstractMap。
public abstract class AbstractMap<K, V> implements Map<K, V> {
// 用懒加载的方式定义了Set集合类型的键,表明HashMap键是不能重复的
Set<K> keySet;
// 用懒加载的方式定义了Collection集合类型的值,表明HashMap值是可以重复的
Collection<V> valuesCollection;
……
}
这里重点要看明白一开始定义的键和值,键是不能重复的,值可以重复。
然后定义了两个静态的实体类
// 维护键和值的 Entry
static class AbstractMap.SimpleEntry<K,V>
// 维护不可变的键和值的 Entry
static class AbstractMap.SimpleImmutableEntry<K,V>
继续下面实现了接口Map中的方法:clear、put、get、equals、size、hashCode等等。
HashMap源码解析
现在我们开始分析HashMap的源码,走起┏ (゜ω゜)=☞
元素定义
private static final int MINIMUM_CAPACITY = 4;// HashMap最小容量为4
private static final