根据数组+链表的原理,自己实现一个简易版的HashMap
前言
昨天被人问到了HashMap底层实现方式,然而自己却只知道用hashCode()方法实现。虽然有看过HashMap源码,但自己却一直没搞懂具体实现方式。于是,从朋友那里借来一本书,专门研究了一下Map,才发现原来底层实现就是“数组 + 链表”的形式(顿时无语,当时自己居然没看出来!!)。
接上两篇“数组 + 链表”,本次还是尝试自己根据其原理来实现一个简易版的HashMap。
HashMap简介
- HashMap底层实现原理
- ‘数组’里面放’链表’,‘链表’里面放的’Entry(key,value)’
- 【注:Java8中,链表长度达到8,并且数组长度达到64,链表将切换为红黑树结构】
- 大致模型
- 数组{链表1, 链表2, 链表3}
- 链表1(Entry1<—>Entry2<—>Entry3) 或红黑树
- Entry1(key, value)
- 查找value的方式
- 先根据key的hashCode对容器size取余数,找到数组里面的链表对象。实际是 (length -1) & hashcode),length为2的n次方时,效果等同,速度更快。
- 再遍历链表,根据key找到value(此时是用的key.equals()进行比较)
代码如下
import java.util.LinkedList;
/**
* 自己实现一个简易版的HashMap
*
* @author ALion
* @version 2017/11/4 16:03
*/
public class MyHashMap<K, V> {
private LinkedList[] arr = new LinkedList[1024];
private int size;
public int size() {
return size;
}
/**
* 存入一个key-value对
*/
public void put(K key, V value) {
MyEntry<K, V> entry = new MyEntry<>(key, value);
int num = (key.hashCode() & 0x7FFFFFFF) % arr.length;//也可以Math.abs(key.hashCode() % arr.length)
// HashMap源码中此处num为 (length - 1) & hash,当length为2的n次方时,和 hash % (length - 1)等价
// HashMap中数组的length总是为2的n次方,由扩容算法决定
// get方法同理
if (arr[num] == null) {
LinkedList list = new LinkedList();
list.add(entry);
arr[num] = list;
} else {
// 此处使用链表,而Java8中还加入了红黑树
LinkedList list = arr[num];
for (Object obj : list) {
MyEntry e = (MyEntry) obj;
if (e.key.equals(key)) {
e.value = value; //如果key相同,就覆盖
return;
}
}
arr[num].add(entry);
}
size++;
}
/**
* 根据key,获取value
*/
public V get(K key) {
int num = (key.hashCode() & 0x7FFFFFFF) % arr.length;//也可以Math.abs(key.hashCode() % arr.length)
if (arr[num] != null) {
LinkedList list = arr[num];
for (Object obj : list) {
MyEntry<K, V> entry = (MyEntry<K, V>) obj;
if (entry.key.equals(key)) {
return entry.value;
}
}
}
return null;
}
/**
* key-value的封装类
*/
static class MyEntry<K, V> {
K key;
V value;
MyEntry(K key, V value) {
this.key = key;
this.value = value;
}
}
}
测试一下
/**
* Main
*
* @author ALion
* @version 2017/11/4 16:02
*/
public class Main {
public static void main(String[] args) {
MyHashMap<String, String> map = new MyHashMap<>();
map.put("zhangsan", "chongqing");
map.put("lisi", "beijing");
map.put("wangwu", "shanghai");
System.out.println(map.get("lisi"));
MyHashMap<String, Integer> map2 = new MyHashMap<>();
map2.put("zhangsan", 18);
map2.put("lisi", 26);
map2.put("lisi", 28);
System.out.println(map2.get("lisi"));
System.out.println(map2.size());
}
}
其他
- 关于元素在数组中的位置的计算示例
int length = 32; // i 即 hashcode for (int i = 1; i < 100; i++) { System.out.println("-------效果相同-------"); System.out.println(i + " % " + length + " = " + (i % length)); System.out.println(length - 1 + " & " + i + " = " + ((length - 1) & i)); }