手写HashMap源码 (jdk 1.8版本)
– 考虑以后手写一下ConcurrentHashMap源码
知识点
- 自己构建出hash冲突现场
- 实现散列数据数据结构
- 理解hash、get、put、resize、remove 等核心方法的设计原理
- 链表转红黑树的时机和过程
- 红黑树退化为链表的时机和过程
如何产生hash冲突呢?
10000000000000000 65536
0000000000000001 高16位
110000000000000010 196610
0000000000000011 高16位
1110000000000000110 458758
0000000000000111 高16位
11110000000000001110 983054
0000000000001111 高16位
111110000000000011110 2031646
0000000000011111 高16位
1111110000000000111110 4128830
0000000000111111 高16位
11111110000000001111110 8323198
0000000001111111 高16位
111111110000000011111110 16711934
0000000011111111 高16位
1111111110000000111111110 33489406
0000000111111111 高16位
hashMap实现源码,基于阅读然后实现
package top.takefly.map;
import top.takefly.tree.printer.BinaryTreeInfo;
import top.takefly.tree.printer.BinaryTrees;
import java.io.Serializable;
import java.util.function.BiConsumer;
/**
* @author 戴灵飞 dailingfei
* @version 1.0
* @date 2020/2/1 13:29
* 模仿hashMap
*/
public class HashMap<K, V> implements Map<K, V>, Serializable, Cloneable {
private static final boolean RED = false;
private static final boolean BLACK = true;
//默认容量
private static final int DEFAULT_CAPACITY = 1 << 4;//16
private transient int size;//容量
private transient int modCount;//修改次数
private static final int TREEIfy_THRESHOLD = 8;
private static final int MIN_TREEIfy_CAPACITY = 1 << 6;
private static final int MAX_CAPACITY = 1 << 30;
private int threshold;
private float loadFactory = 0.75f;
private transient Node<K, V>[] table;//哈希表 也称散列表
/**
* @return
*/
private Node<K, V>[] resize() {
Node<K, V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
if (oldCap >= MAX_CAPACITY) {//不允许继续扩容
newThr = Integer.MAX_VALUE;//将扩容限制设置到最高
return oldTab;
} else if ((newCap = (oldCap << 1)) <= MAX_CAPACITY
&& oldCap >= DEFAULT_CAPACITY) {//允许扩容一倍
newThr = oldThr << 1;
}
} else if (oldThr > 0) {
newCap = oldThr;
} else { //oldThr <= 0 && oldCap <= 0
newCap = DEFAULT_CAPACITY;//第一次初始化为默认容量
newThr = (int) (DEFAULT_CAPACITY * loadFactory);
}
if (newThr == 0) {
float ft = (float) (newCap * loadFactory);
newThr = (newCap < MAX_CAPACITY && ft < MAX_CAPACITY) ? (int) ft : Integer.MAX_VALUE;
}
Node<K, V>[] newTable = new Node[newCap];//创建新的hash表(散列表)
table = newTable;//table新的hash表
threshold = newThr;
if (oldTab != null) {
System.out.println("---------resize 开始----------------");
System.out.println("newCap:" + newCap + ",oldCap:" + oldCap);
System.out.println();
for (int i = 0; i < oldCap; i++) {//遍历整个old散列表 i 表示索引
Node<K, V> e;
if ((e = oldTab[i]) != null) {
oldTab[i] = null;//let gc work
if (e.next == null)
newTable[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode) {
((TreeNode<K, V>) e).split(this, newCap, i, oldCap);
} else {//单链表处理
Node<K, V> loHead = null, loTail = null;//低列链表
Node<K, V> hiHead = null, hiTail = null, next = null;//低列链表
do {
//因为capacity是2的幂 所以log(capacity)为多少就表示对应的二进制有多少0
//之所以拿元素的hash与oldCap按位与运算,就是判断下一位是否为1
next = e.next;
if ((e.hash & oldCap) == 0) {//下一位为0
if (loHead == null) {
loHead = e;
} else {
loTail.next = e;
}
loTail = e;
} else {
if (hiHead == null) {
hiHead = e;
} else {
hiTail.next = e;
}
hiTail = e;
}
} while ((e = next) != null);
if (loHead != null) {//所在索引不变
loTail.next = null;
newTable[i] = loHead;
}
if (hiHead != null) {//上升到oldCap+i
hiTail.next = null;
newTable[i + oldCap] = hiHead;
}
if(newCap == 32769){
System.out.print("loHead");
while (loHead != null) {
System.out.print("->" + loHead + ":" + ((newCap - 1) & loHead.hash));
loHead = loHead.next;
}
System.out.println();
System.out.print("hiHead");
while (hiHead != null) {
System.out.print("->" + hiHead + ":" + ((newCap - 1) & hiHead.hash));
hiHead = hiHead.next;
}
System.out.println();
}
}
}
}
System.out.println("---------resize 结束----------------");
System.out.println();
}
return newTable;
}
private static class Node<K, V> {
int hash;
K key;
V value;
protected Node<K, V> next;
Node(int hash, K key, V value, Node<K, V> next) {
this.next = next;
this.hash = hash;
this.key = key;
this.value = value;
}
@Override
public String toString() {
return key.toString() + "_" + hash;
}
}
private static class TreeNode<K, V> extends Node<K, V> {
boolean red = true;
public TreeNode<K, V> pre;
public TreeNode<K, V> parent;
public TreeNode<K, V> left;
public TreeNode<K, V> right;
TreeNode(int hash, K k, V v, Node<K, V> next) {
super(hash, k, v, next);
}
TreeNode(int hash, K k, V v, TreeNode<K, V> parent) {
super(hash, k, v, null);
this.parent = parent;
}
@Override
public String toString() {
String color = red ? "Red" : "Black";
K p = parent == null ? null : parent.key;
K l = left == null ? null : left.key;
K r = right == null ? null : right.key;
K n = next == null ? null : next.key;
// return color + "_k(" + key + ")_p(" + p + ")_l(" + l + ")_r(" + r + ")";
// return color + "_k(" + key + ")_n(" + n + ")";
return key + "_";
}
public Node<K, V> putVal(int hash, K k, V value) {
return null;
}
/**
* 将双向链表转化为红黑树
*/
public void treeify(Node<K, V>[] tab) {//树状化
TreeNode<K, V> root = null;
for (TreeNode<K, V> x = this, next; x != null; x = next) {
next = (TreeNode<K, V>) x.next;
if (root == null) {//添加到根节点
x.parent = null;
x.red = false;//设置为黑色
root = x;//根节点
} else {//非跟节点添加
K k = x.key;
int h = x.hash;
int cmp = 0;
Class<?> kc;
for (TreeNode<K, V> p = root; ; ) {//遍历
int ph = p.hash;
K pk = p.key;
if (ph < h) {
cmp = 1;
} else if (ph > h) {
cmp = -1;
} else if (k == null
&& (
(kc = comparableClassFor(k)) == null || (cmp = compareComparables(kc, k, pk)) == 0)) {
cmp = tieBreakOrder(k, pk);
}
TreeNode<K, V> xp = p;//保存父节点
if ((p = (cmp <= 0) ? p.left : p.right) == null) {
x.parent = xp;//x 表示要插入的节点
if (cmp <= 0) {
xp.left = x;
} else {
xp.right = x;
}
root = balanceInsertion(root, x);//插入节点后平衡
break;
}
}
}
}
moveRootToFront(tab, root);//将root节点移动到对应索引的第一个
}
/**
* 将root节点移到桶的前面
*
* @param tab
* @param root
*/
public void moveRootToFront(Node<K, V>[] tab, TreeNode<K, V> root) {
int n, index;// n:用于记录hash表大小 index:用于记录root的索引
if (tab != null && (n = tab.length) != 0) {
TreeNode<K, V> first = (TreeNode<K, V>) tab[index = (n - 1) & root.hash];
if (first != root) {//说明root不是根节点
Node<K, V> rn;
tab[index] = root;//指定root为根节点
TreeNode<K, V> rp = root.pre;
if ((rn = root.next) != null) {
((TreeNode<K, V>) rn).pre = pre;
}
if (rp != null) {
rp.next = rn;
}
if (first != null) {
first.pre = root;
}
root.next = first;
root.pre = null;
TreeNode<K, V> finalRoot = root;
BinaryTrees.println(new BinaryTreeInfo() {
@Override
public Object root() {
return finalRoot;
}
@Override
public Object left(Object node) {
return ((TreeNode) node).left;
}
@Override
public Object right(Object node) {
return ((TreeNode) node).right;
}
@Override
public Object string(Object node) {
return node;
}
});
System.out.println(root);
}
}
}
//平衡新插入的节点 红黑树处理插入有12中情况
static <K, V> TreeNode<K, V> balanceInsertion(TreeNode<K, V> root,
TreeNode<K, V> x) {
x.red = true;
//xp表示父节点 xpp表示祖父节点 xppl表示祖父节点的左节点 xppr表示祖父节点右节点
for (TreeNode<K, V> xp, xpp, xppl, xppr; ; ) {//非递归处理节点插入时,上溢的问题
if ((xp = x.parent) == null) {
x.red = false;//父节点为空,直接将父节点染成黑色,并返回
return x;
} else if (!xp.red || (xpp = xp.parent) == null)//父节点为黑色,不做处理
return root;
if (xp == (xppl = xpp.left)) {//父节点是祖父节点的左边 xppl表示为当前节点的祖父节点
if ((xppr = xpp.right) != null && xppr.red) {//xppr为x的uncle节点,并且为红色
//处理为:将自己父节点、uncle节点染成黑色,祖父节点染成红色 , 并且赋给x 继续处理逻辑(递归逻辑 非递归化)
xppr.red = false;
xp.red = false;
xpp.red = true;
x = xpp;
} else {//uncle不存在或者非红色 就是黑色
if (x == xp.right) {//父节点是祖先节点左边,当前节点是父节点的右边LR,需要将右边这种情况转换为 LL
root = rotateLeft(root, x = xp);//需要终止 所以需要将xp赋给x
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {//右旋 LL 父节点
xp.red = false;//父节点染尘黑色 类似于先将自己染成黑色 因为是先旋转 才染的色, 原来的x变为了父节点
if (xpp != null) {
xpp.red = true;//祖先节点染成红色
root = rotateRight(root, xpp);//祖先节点向右旋转
}
}
}
} else {//父节点是祖父节点的右边
if (xppl != null && xppl.red) {
xppl.red = false;
xp.red = false;
xpp.red = true;
x = xpp;
} else {
if (x == xp.left) {
root = rotateRight(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateLeft(root, xpp);
}
}
}
}
}
}
static <K, V> TreeNode<K, V> rotateLeft(TreeNode<K, V> root,
TreeNode<K, V> p) {
TreeNode<K, V> r, pp, rl;
if (p != null && (r = p.right) != null) {
if ((rl = p.right = r.left) != null)
rl.parent = p;
if ((pp = r.parent = p.parent) == null)
(root = r).red = false;
else if (pp.left == p)
pp.left = r;
else
pp.right = r;
r.left = p;
p.parent = r;
}
return root;
}
static <K, V> TreeNode<K, V> rotateRight(TreeNode<K, V> root,
TreeNode<K, V> p) {
TreeNode<K, V> l, pp, lr;
if (p != null && (l = p.left) != null) {
if ((lr = p.left = l.right) != null)
lr.parent = p;
if ((pp = l.parent = p.parent) == null)
(root = l).red = false;
else if (pp.right == p)
pp.right = l;
else
pp.left = l;
l.right = p;
p.parent = l;
}
return root;
}
/**
* @param k 表示待插入的节点的key
* @param pk 红黑树节点的key
* @return
*/
public int tieBreakOrder(Object k, Object pk) {
int d;
if (k == null || pk == null ||
(d = k.getClass().getName()
.compareTo(pk.getClass().getName())) == 0) {//k或pk其中都不为null就用类名来进行比较
d = System.identityHashCode(k) <= System.identityHashCode(pk) ? -1 : 1;//k不为null,pk为null //k为null , pk不为null
}
return d;
}
public int compareComparables(Class<?> kc, Object k, Object x) {
return (x == null || x.getClass() != kc ? 0 : ((Comparable) k).compareTo(x));//判断
}
public Class<?> comparableClassFor(K k) {
if (k instanceof Comparable) {
return k.getClass();
}
return null;
}
public Node<K, V> find(int hash, K key) {
return parent == null ? root() : find(hash, key, null);
}
private Node<K, V> find(int hash, K key, Class<?> kc) {
TreeNode<K, V> p = this;
do {
int ph = p.hash;
K pk = p.key;
int cmp = 0;
TreeNode<K, V> pr = p.right, pl = p.left;
if (ph < hash) {
p = pr;
} else if (ph > hash) {
p = pl;
} else if (pl == null) {
p = pr;
} else if (pr == null) {
p = pl;
} else if (ph == hash && (key == p.key || (key != null && key.equals(pk)))) {
return p;
} else if (kc != null
&& ((kc = comparableClassFor(key)) != null)
&& (cmp = compareComparables(kc, key, kc)) != 0) {
p = (cmp < 0) ? p.left : p.right;
} else if ((p = (TreeNode<K, V>) pl.find(hash, key, kc)) != null) {
return p;
} else {
p = pr;
}
} while (p != null);
return null;
}
private TreeNode<K, V> root() {
for (TreeNode<K, V> r = this; ; ) {
if (r.parent == null) {
return r;
}
r = r.parent;
}
}
/**
* 出现了问题
*
* @param value
* @return
*/
public boolean containsValue(V value) {
return (parent != null ? root() : this).innerContainsValue(value);
}
private boolean innerContainsValue(V value) {
TreeNode<K, V> p = this;
do {
if (p.value == value || (value != null && value.equals(p.value))) return true;
} while ((p = (TreeNode<K, V>) p.next) != null);
return false;
}
/**
* 删除当前节点
*
* @param map
* @param tab
* @param moved
*/
public void removeTreeNode(HashMap<K, V> map, Node<K, V>[] tab, boolean moved) {
//维护前驱和后继
}
public void split(HashMap<K, V> map, int newCap, int i, int oldCap) {
}
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean containsKey(K key) {
return getNode(hash(key), key) != null;
}
@Override
public boolean containsValue(V value) {
Node<K, V>[] tab;
int n;
if ((tab = table) != null && (n = table.length) != 0) {
Node<K, V> first = null, e, next;
for (int i = 0; i < n; i++) {
if ((first = tab[i]) != null) {
//第一个元素的value是否等于value
if (first.value == value || (value != null && value.equals(first.value)))
return true;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode) first).containsValue(value);
do {
if (first.value == value || (value != null && value.equals(first.value)))
return true;
} while ((e = e.next) != null);
}
}
}
}
return false;
}
@Override
public V put(K key, V v) {
return putVal(hash(key), key, v);
}
private V putVal(int hash, K key, V value) {
Node<K, V>[] tab;//指向哈希表
Node<K, V> p;//
int n, index;
if ((tab = table) == null || (n = table.length) == 0) {
n = (tab = resize()).length;
}
//(n - 1) & hash
if ((p = tab[index = (n - 1) & hash]) == null) {//当前索引所在的hash桶不存在数据
tab[index] = newNode(hash, key, value, null);
} else {
Node<K, V> e;//用于存储需要覆盖的
K k;//保存键值
if ((k = p.key) == key || (k != null && k.equals(key)))
e = p;
else if (p instanceof TreeNode)//红黑树的元素插入方式
e = ((TreeNode<K, V>) p).putVal(hash, k, value);
else {
for (int binCount = 1; ; binCount++) {//binCount单链表中元素个数
if ((e = p.next) == null) {//判断是否为链表尾部 , //e为空
p.next = new Node<K, V>(hash, key, value, null);
if (binCount >= TREEIfy_THRESHOLD) {//单链表中元素个数是否大于阈值
treeifyBin(tab, hash);//单链表转化为红黑树
}
break;
}
//判定两个key相等
if ((k = e.key) == key || (k != null && k.equals(key))) {
break;
}
p = e;
}
}
if (e != null) {
V oldValue = e.value;//保存旧值
e.value = value;
return oldValue;
}
}
size++;//元素个数增加
if (size >= threshold) {
resize();
}
//涉及到需要扩容
modCount++;
return null;
}
protected Node<K, V> newNode(int hash, K key, V value, Node<K, V> next) {
return new Node<>(hash, key, value, next);
}
private void treeifyBin(Node<K, V>[] tab, int hash) {
int n, index;
Node<K, V> e;//用于存储临时节点
if (tab == null || (n = tab.length) < MIN_TREEIfy_CAPACITY) {
resize();//重新计算容量
} else if ((e = tab[index = (n - 1) & hash]) != null) {
TreeNode<K, V> tl, hd;
tl = hd = null;//tl tail表示尾部 , hd:head表示头部
do {
TreeNode<K, V> p = replacementTreeNode(e, null);
if (hd == null) {
hd = p;
} else {
tl.next = p;
p.pre = tl;
}
tl = p;//tl指向尾部
} while ((e = e.next) != null);//判断
TreeNode<K, V> curNode = hd;
System.out.print("start");
while (curNode != null) {
System.out.print("->" + curNode + ":" + ((n - 1) & curNode.hash));
curNode = (TreeNode<K, V>) curNode.next;
}
System.out.println();
if ((tab[index] = hd) != null) {
hd.treeify(tab);//树状化 红黑树化
}
}
}
private TreeNode<K, V> replacementTreeNode(Node<K, V> e, Node<K, V> next) {
return new TreeNode<K, V>(e.hash, e.key, e.value, next);
}
//对得到的hashcode进行高位和低位异或计算
public int hash(Object key) {
int h;
return (h = key.hashCode()) ^ (h >>> 16);
}
@Override
public V remove(K key) {
Node<K, V> e;
return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value;
}
//hashMap中删除的思想是先找到这个节点,再调用节点的删除逻辑
private Node<K, V> removeNode(int hash, Object key, Object value, boolean matchValue, boolean moved) {
Node<K, V>[] tab;
int n, index;
if ((tab = table) != null && (n = table.length) != 0) {
Node<K, V> e = null, p, node = null;/*node:保存需要刪除的节点*/
if ((p = tab[index = (n - 1) & (hash = hash(key))]) != null) {
if (p.hash == hash && (key == p.key || (key != null && key.equals(p.key))))
node = p;
else if ((e = p.next) != null) {//下一个节点不为空
if (p instanceof TreeNode)
node = ((TreeNode) p).find(hash, key);
else {//为单链表
do {
if (e.hash == hash && (e.key == key || (key != null && key.equals(e.key)))) {
node = e;//要删除的节点
break;
}
p = e; //p表示记录前一个节点,作用是用于删除元素
} while ((e = e.next) != null);
}
}
//是否找到待删除的节点
if (node != null &&
(!matchValue ||
(value == node.value ||
(value != null && value.equals(node.value))))) {
if (node instanceof TreeNode) {
((TreeNode) node).removeTreeNode(this, tab, moved);
} else if (node == p) {//第一个节点就是待删除的节点,同时不失TreeNode节点
tab[index] = node.next;
} else {//待删除的不是第一个节点
p.next = node.next;
}
size--;
modCount++;
return node;
}
}
}
return null;
}
@Override
public V get(K key) {
Node<K, V> e;
return ((e = getNode(hash(key), key)) == null) ? null : e.value;
}
/**
* @return
*/
private Node<K, V> getNode(int hash, K key) {
Node<K, V>[] tab;
int n;
if ((tab = table) != null && (n = table.length) != 0) {
Node<K, V> e;
if ((e = tab[(n - 1) & hash]) != null) {
if (e.hash == hash && (key == null ? key == e.key : key.equals(e.key)))
return e;
if ((e = e.next) != null) {//下一个节点不为空
if (e instanceof TreeNode)//红黑树搜索
return ((TreeNode<K, V>) e).find(hash, key);
do {//单链表搜索
if (e.hash == hash && (e.key == key || (key != null && key.equals(e.key))))
return e;
} while ((e = e.next) != null);
}
}
}
return null;
}
@Override
public void clear() {
int size;
}
@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
Node<K, V>[] tab;
int n;
if ((tab = table) != null && (n = tab.length) != 0) {
Node<K, V> e = null;
for (int i = 0; i < n; i++) {
if ((e = tab[i]) != null && e instanceof TreeNode) {
final TreeNode<K, V> finalE = (TreeNode<K, V>) e;
BinaryTrees.println(new BinaryTreeInfo() {
@Override
public Object root() {
return finalE;
}
@Override
public Object left(Object node) {
return finalE.left;
}
@Override
public Object right(Object node) {
return finalE.right;
}
@Override
public Object string(Object node) {
return finalE;
}
});
}
}
}
}
public void display() {
Node<K, V>[] tab;
int n;
if ((tab = table) != null && (n = tab.length) != 0) {
Node<K, V> e = null;
for (int i = 0; i < n; i++) {
if ((e = tab[i]) != null && e instanceof TreeNode) {
final TreeNode<K, V> finalE = (TreeNode<K, V>) e;
BinaryTrees.println(new BinaryTreeInfo() {
@Override
public Object root() {
return finalE;
}
@Override
public Object left(Object node) {
return ((TreeNode) node).left;
}
@Override
public Object right(Object node) {
return ((TreeNode) node).right;
}
@Override
public Object string(Object node) {
return node;
}
});
}
}
}
}
}
此源码的编写是为了实践散列数据结构和更加深层次了解HashMap底层设计原理和设计思想
其中display方法是可以打印红黑树的结构图,如果需要具体源码,可以在评论区留言哦