java1.8是现在用的最多的版本,HashMap是现在用的最多的map,HashMap的源码可以说是面试必备技能,今天我们试图分析一下源码。
之前我们分析java1.7的hashMap说它有一个问题,链表过长,java8引入了红黑树解决
结构:数组加链表,链表过长时裂变为红黑树
一、先看整体的数据结构
首先我们注意到数据是存放在一个Node数组里面
transient Node[] table;
接着我们看一下Node的结构
static class Node implements Map.Entry {
final int hash;
final K key;
V value;
Node next;
Node(int hash, K key, V value, Node next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry,?> e = (Map.Entry,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
我们注意到这是一个单链表,next指向下一个节点。
二、我们先看简单的get方法
接着我们看一下get(Object key)方法
public V get(Object key) {
Node e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
实际调用的getNode方法
final Node getNode(int hash, Object key) {
Node[] tab; Node first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
我们来一步步分析,首先定位到数据在数组的下标:(n - 1) & hash
找到数组的第一个node:first
first = tab[(n - 1) & hash]
如果first为null直接返回 如果first的key和get里面的key相等,则返回first的value
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
如果first的key和get里面的key不相等,判断first是不是TreeNode,如果不是,则一直找链表的next,直到key和所传的key相等
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
如果first的key和get里面的key不相等,判断first是不是TreeNode,如果是,则调用getTreeNode方法查找
if (first instanceof TreeNode)
return ((TreeNode)first).getTreeNode(hash, key);
我们看一下TreeNode的数据结构
static final class TreeNode extends LinkedHas