手写代码:HashMap
一、简介
1、原理解析
Entry[ ] table 就是HashMap的核心数组结构,我们也称之为“位桶数组”;
一个Entry对象存储了:
-
key:键对象 value:值对象
-
next:下一个节点
-
hash: 键对象的hash值
显然每一个Entry对象就是一个单向链表结构,我们使用图形表示一个Entry对象的典型示意:
然后,我们画出Entry[]数组的结构(这也是HashMap的结构):
存储过程
2、单个方法原理解析
1、根据key的hash值,确定存储的位置(取模)
根据key的hash值,取模确定一个值(值小于桶),实现随机存储在桶中;
2、存储元素(key-value)
创建存储对象,添加值到Node元素对象中,存的过程分为三种情况。
(1): 获取的桶元素为空,直接将当前元素存进去即可;
(2): 遍历当前桶中元素,如果有相同key,则把value值进行替换;
(3): 遍历当前桶中元素,如果没有重复的key,则把值添加到最后;
3、重写toString方法
创建StringBuilder进行存储,遍历桶,再将桶中的链表的进行遍历,取出其中存储的value的值,进行返回;
4、get方法
根据1、方法获取key特定的hash值,找到指定的桶,遍历其中的链表,根据key的值,取出value值返回即可。
二、实现的代码
Node
public class Node<K, V> {
public int hash; //key的hash值
public K key; //key键的的值
public V value; //存储的value值
public Node next; //下一个元素的地址值
}
HashMap
public class MyHashMap<K, V> {
Node[] table; //位桶数组
int size; //存放的键值对的个数
public MyHashMap() {
table = new Node[16];
}
public MyHashMap(Node[] table, int size) {
this.table = table;
this.size = size;
}
// 1、根据key的hash值,确定存储的位置(取模)
private int myHash(int v, int length) {
return v & (length - 1);
}
// 2、存储元素(key-value)
public void put(K key, V value) {
// -1、创建存储的对象,并把值放进去
Node newNode = new Node();
newNode.hash = myHash(key.hashCode(), table.length);
newNode.key = key;
newNode.value = value;
newNode.next = null;
// -2、将有值的对象,放进hashMap对象的存储位置中
Node temp = table[newNode.hash];
Node iterLast = null; //正在遍历的最后一个元素
boolean keyRepeat = false;
if (temp == null) {
//1、此处数组元素为空,则直接将节点放进去
table[newNode.hash] = newNode;
size++;
} else {
// 2、此处数组元素不为空。则遍历对应链表
while (temp != null) {
if (temp.key.equals(key)) {
keyRepeat = true;
temp.value = value; //只是覆盖value的值即可。其他的(hash,key,next)值保持不变
break;
} else {
// key不重复,则遍历下一个
iterLast = temp;
temp = temp.next;
}
}
// 3、没有发生key重复的情况,则添加到链表的最后
if (!keyRepeat) {
iterLast.next = newNode;
size++;
}
}
}
// 3、重写toString方法
@Override
public String toString() {
StringBuilder sb = new StringBuilder("{");
// 遍历bucket数组
for (int i = 0; i < table.length; i++) {
Node temp = table[i];
// 遍历链表
while (temp != null) {
sb.append(temp.key + ":" + temp.value);
temp = temp.next;
}
}
sb.setCharAt(sb.length() - 1, '}');
return sb.toString();
}
// 4、get方法
public V get(K key) {
int hash = myHash(key.hashCode(), table.length);
V value = null;
if (table[hash] != null) {
Node temp = table[hash];
while (temp != null) {
// 相等:则说明找到了键值对,返回相应的value值
if (key.equals(temp.key)) {
value = (V) temp.value;
break;
} else {
temp = temp.next;
}
}
}
return value;
}
}