通过实现自己的HashMap彻底了解HashMap的底层原理
- JDK1.8 HashMap通过数组、链表、红黑树结构实现
- 了解它的动态扩容、hash算法、存入元素、取出元素的过程
代码简单实现(省去树化,rehash):
public interface IMap<K,V> {
void put(K k, V v);
V get(Object k);
void remove(Object k);
int size();
}
public class MyHashMap<K ,V> implements IMap<K, V>{
private final static int DEFAULT_CAPACITY = 1 << 3;
private Node<K,V>[] table;
private int size;
static class Node<K,V> {
final K k;
V v;
Node<K,V> next;
public Node(K k, V v, Node<K, V> next) {
this.k = k;
this.v = v;
this.next = next;
}
@Override
public String toString() {
return "Node{" +
"k=" + k +
", v=" + v +
", next=" + next +
'}';
}
}
@Override
public void put(K k, V v) {
Node<K,V>[] tab;
Node<K,V> p;
int i, n, h;
//如果哈希表为null,在resize里面进行初始化
if ((tab = table) == null || (n = table.length) == 0) {
n = (tab = resize()).length;
}
//元素下标对应的位置中没有元素,直接入桶
if ((p = tab[i = ((h = hash(k)) & (n-1))]) == null) {
tab[i] = new Node<>(k,v,null);
}else {
//否则发生哈希碰撞,进行判断k是否相同
Node<K,V> e;
K k1;
int hash = hash(k1 = p.k);
//与哈希桶中k相同,e!=null
if (hash == h && (Objects.equals(k, k1))) {
//Objects.equals(k, k1) --> return (a == b) || (a != null && a.equals(b));
e = p;
}else {
//将新元素连到链表中
while (true) {
//链表中k不重复,e == null
if ((e = p.next) == null) {
p.next = new Node<>(k,v,null);
break;
}
//与链表中k相同,e!=null
if (hash(e.k) == h && Objects.equals(e.k,k)) {
break;
}
p = e;
}
}
//k值相同,进行value的替换
if (e != null) {
e.v =v;
//重复的k,size不进行++操作,直接return
return;
}
}
if (++size > table.length) {
resize();
}
}
private int hash(Object k) {
return k == null ? 0 : k.hashCode() ^ (k.hashCode()>>>16);
//return 1;
}
private Node<K,V>[] resize() {
Node<K,V>[] oldTable = table;
int oldCap = (oldTable == null) ? 0 : oldTable.length;
int newCap = 0;
if (oldCap > 0) {
newCap = oldCap << 1;
}else {
newCap = DEFAULT_CAPACITY;
}
@SuppressWarnings("unchecked")
Node<K,V>[] newTable = (Node<K,V>[])new Node[newCap];
table = newTable;
if (oldTable != null) {
//rehash
//waiting...
}
return newTable;
}
@Override
public V get(Object k) {
Node<K,V> e;
return (e = getNode(hash(k),k)) == null ? null : e.v;
}
private Node<K,V> getNode(int hash, Object k) {
if (table == null || table.length == 0 || table[hash&(table.length - 1)] == null) {
return null;
}
Node<K,V> first = table[hash&(table.length - 1)];
if (hash(first.k) == hash && Objects.equals(first.k,k)) {
return first;
}
Node<K,V> e;
if ((e = first.next) != null) {
do {
if (hash(e.k) == hash && Objects.equals(e.k,k)) {
return e;
}
}while ((e = e.next) != null);
}
return null;
}
@Override
public void remove(Object k) {
//waiting...
}
@Override
public int size() {
return size;
}
@Override
public String toString() {
return "MyHashMap{" +
"table=" + Arrays.toString(table) +
'}';
}
}
- 测试结果:
public class Test {
public static void main(String[] args) {
MyHashMap<String,String> map = new MyHashMap<>();
map.put("k1","v1");
map.put("k2","v2");
System.out.println(map.get("k1"));
System.out.println(map.get("k2"));
System.out.println(map.size());
System.out.println(map);
map.put("k2","vv");
map.put("k3","v3");
map.put("kk","vv");
map.put("k1",null);
System.out.println(map.get("k2"));
System.out.println(map.get("k1"));
System.out.println(map.size());
System.out.println(map);
map.put(null,null);
System.out.println(map.size());
System.out.println(map);
/**
* 结果:
* v1
* v2
* 2
* MyHashMap{table=[null, null, null, null, null, null, Node{k=k1, v=v1, next=null}, Node{k=k2, v=v2, next=null}]}
* vv
* null
* 4
* MyHashMap{table=[Node{k=k3, v=v3, next=Node{k=kk, v=vv, next=null}}, null, null, null, null, null, Node{k=k1, v=null, next=null}, Node{k=k2, v=vv, next=null}]}
* 5
* MyHashMap{table=[Node{k=k3, v=v3, next=Node{k=kk, v=vv, next=Node{k=null, v=null, next=null}}}, null, null, null, null, null, Node{k=k1, v=null, next=null}, Node{k=k2, v=vv, next=null}]}
*
*
*/
/**
* 测试哈希碰撞结果:(将hash()直接return 1;)
* v1
* v2
* 2
* MyHashMap{table=[null, Node{k=k1, v=v1, next=Node{k=k2, v=v2, next=null}}, null, null, null, null, null, null]}
* vv
* null
* 4
* MyHashMap{table=[null, Node{k=k1, v=null, next=Node{k=k2, v=vv, next=Node{k=k3, v=v3, next=Node{k=kk, v=vv, next=null}}}}, null, null, null, null, null, null]}
* 5
* MyHashMap{table=[null, Node{k=k1, v=null, next=Node{k=k2, v=vv, next=Node{k=k3, v=v3, next=Node{k=kk, v=vv, next=Node{k=null, v=null, next=null}}}}}, null, null, null, null, null, null]}
*
*/
}