前言
HashMap实现了Map接口,我们常用来put/get操作读存键值对数据,比较典型的key-value结构,那么本文将详细分析此数据结构的底层原理及实现,包括底层存储原理,哈希算法,哈希冲突,源码等等。
一、HashMap是什么?
HashMap实际上是一种数组+链表(jdk1.8后加入红黑树)的一种数据结构,在put操作中通过内部定义的算法(哈希算法)找到数组的下标,将数组放在此数组元素中,如果该数组元素已经有了元素(hash冲突),将会把这个数组元素上的链表进行遍历,放在此链表的末尾,内部有next code下一步节点,根据这个来定义位置。
二、 数组
简单的说:数组就是采用一段连续的存储单元来存储数据。 特点:查询快O(1),删除插入慢O(N)
查询快:因为数组是有自增的下标(索引),查询的时候可以依据索引直接定位到要查询的数据,因此从查询的角度来说效率更高。
删除插入慢:因为:当插入或者删除数据的时候,其他的数据会重新计算下标,重新移位,时间复杂度就是O(N),假设有一个大小为10的数组,当要在下标4~5之间插入数据时,新数据的下标就为6,而原本为6的数据下标则为7,以此类推在6后面的所有数据都要重新移位,计算下标,除非插入和删除的是最后一个数据。
自己画的一个潦草的图
实际上ArrayList底层就是一个数组实现。
private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = new Object[0];
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
transient Object[] elementData; // 数组
private int size;
private static final int MAX_ARRAY_SIZE = 2147483639;
/** arraylist的add方法 **/
public boolean add(E var1) {
this.ensureCapacityInternal(this.size + 1);
this.elementData[this.size++] = var1;
return true;
}
上面代码是jdk1.8的源码,可以看到“elementData”实际上就是一个数组,所以arrayList的底层实现实际上也是一个数组,也具有查询快,删除插入慢的特性。
三、 链表
是一种根据元素节点逻辑关系排列的一种数据结构,可以保存多个数据,有点像数组的概念,但是数组有个一个缺点——数组的长度 是固定的,不可改变,在长度固定的情况下首选肯定是数组,但是在开发中有时候保存的内容长度是不确定的,这个时候就能用链表来代替数组使用。
/** 每一个链表实际上就是多个节点 **/
class Node {
/** 保存数据 **/
private String data;
/** 保存下一个节点 **/
private Node nextCode;
/** 每一个Node都必须保存有数据 **/
public Node(String data){
this.data = data ;
}
public void setNextCode(Node nextCode){
this.nextCode = nextCode ;
}
public Node getNextCode(){
return this.nextCode ;
}
public String getData(){
return this.data ;
}
}
public class LinkedList