在手搓之前需要先简单的了解一下这个hashmap到底是什么结构,他的结构构成也就是我们通常意义讲的键值对,即<key,value>这样的形式,我以前一直以为只有一个键值对但是我怎么想都不太明白,一个键值对咋能把功能实行完整,经过一番了解,原来是两层键值对关系,先画一个简单的示意图(AI代画)
![image]()
hashmap是由数组和链表组成的,从图中可以看出数组对应的就是索引下标,然后后面跟着装着数据的链表,数组这个东西查询比较块但是其余的功能需要遍历,效率比较低,但是链表因为指针的存在,修改指向方向就可以轻易做到增删改,速度很快,所以我个人认为hashmap集成了这两个东西的优点。
左边的索引对应数组,优势是查询速度块可以很快,一个索引对应一个桶,这就是外面的第一层键值对,然后桶中有链表,链表中的节点Node<K,V>这是第二层键值对
接下来需要引入一个东西叫哈希碰撞,是当你这个数据经过哈希函数计算后的索引与另一个数据相撞出现的情况就叫哈希碰撞,他们会按进入顺序在头节点后面形成链表,然后引入红黑树,始终对链表形成的树加以控制,就可以完成高效的查询(虽然还是没数组快),但也比O(n)快,这就是hashmap极致的单线程效率,多线程就炸了,也就是为什么会出现concurrenthashmap的原因,这个先暂且不提。下面是一部分的手搓过程,因为比较难,还在研究中。
首先第一步肯定是先确定变量然后初始化这些
1. 定义节点类 (链表的节点)
static class Node<K, V> {
final int hash; //哈希函数
final K key; //key
V value; //value
Node<K, V> next; //指针
构造器
Node(int hash, K key, V value, Node<K, V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
}
2. 核心属性
// 初始容量 (默认16)
private static final int DEFAULT_CAPACITY = 16;
// 负载因子 (超过这个比例就扩容)
private static final float LOAD_FACTOR = 0.75f;
// 桶数组 (核心存储结构)
private Node<K, V>[] table;
// 元素个数
private int size;
// 扩容阈值 (size > threshold 就扩容)
private int threshold;
3. 构造函数
@SuppressWarnings("unchecked") //这个东西使用去掉黄色波浪线的
public SimpleHashMap() {
// 创建数组
table = (Node<K, V>[]) new Node[DEFAULT_CAPACITY];
// 设置阈值
threshold = (int) (DEFAULT_CAPACITY * LOAD_FACTOR);
}
前置工作准备完毕,方法下次再写,因为还没研究明白