删除数据
public V remove(Object key)
final Node<K,V> removeNode(int hash, Object key, Object value, boolean matchValue, boolean movable)
/**
* Removes the mapping for the specified key from this map if present.
*
* @param key key whose mapping is to be removed from the map
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V remove(Object key) {
Node<K,V> e;
return (e = removeNode(hash(key), key, null, false, true)) == null ?
null : e.value;
}
/**
* Implements Map.remove and related methods.
*
* @param hash hash for key
* @param key the key
* @param value the value to match if matchValue, else ignored
* @param matchValue if true only remove if value is equal
* @param movable if false do not move other nodes while removing
* @return the node, or null if none
*/
final Node<K,V> removeNode(int hash, Object key, Object value,
boolean matchValue, boolean movable) {
Node<K,V>[] tab; Node<K,V> p; int n, index;
//校验table不为空,并且table上对应的索引值不为空
if ((tab = table) != null && (n = tab.length) > 0 &&
(p = tab[index = (n - 1) & hash]) != null) {
Node<K,V> node = null, e; K k; V v;
//判断key对应的key值是否正确且不为空,是的话赋值给node
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
node = p;
else if ((e = p.next) != null) {
//判断当前是否树化,如树化,getTreeNode获得对应节点。
if (p instanceof TreeNode)
node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
else {
do {
//如果没树化,是链表就遍历链表找到对应的key的节点,赋值给node
if (e.hash == hash &&
((k = e.key) == key ||
(key != null && key.equals(k)))) {
node = e;
break;
}
p = e;
} while ((e = e.next) != null);
}
}
//判断node是否为空,并且对应的值是否相等,如果树化了就调用removeTreeNode移除树的节点。
//如果key在当前tab的索引位置,直接覆盖,否则p.next = node.next移除node
if (node != null && (!matchValue || (v = node.value) == value ||
(value != null && value.equals(v)))) {
if (node instanceof TreeNode)
((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
else if (node == p)
tab[index] = node.next;
else
p.next = node.next;
++modCount;
--size;
afterNodeRemoval(node);
return node;
}
}
return null;
}
afterNodeRemoval方法默认是空实现
// Callbacks to allow LinkedHashMap post-actions
void afterNodeAccess(Node<K,V> p) { }
void afterNodeInsertion(boolean evict) { }
void afterNodeRemoval(Node<K,V> p) { }
TreeNode
继承LinkedHashMap.Entry<K,V>,而后者又继承了Hashmap.Node<K,V>。所以TreeNode有Node属性,并且由于添加了prev这个前驱指针使得链表变成双向的。
TreeNode<K,V> root()
/**
* Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
* extends Node) so can be used as extension of either regular or
* linked node.
*/
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
//父节点,左、右节点删除后断开连接,red:是否是红黑树的红节点
TreeNode<K,V> parent; // red-black tree links
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev; // needed to unlink next upon deletion
boolean red;
TreeNode(int hash, K key, V val, Node<K,V> next) {
super(hash, key, val, next);
}
//这里是LinkedHashMap里Entry<K,V>
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
//返回根节点,检查parent是否为null,为null就是根节点。
/**
* Returns root of tree containing this node.
*/
final TreeNode<K,V> root() {
for (TreeNode<K,V> r = this, p;;) {
if ((p = r.parent) == null)
return r;
r = p;
}
}
getTreeNode
第2行p赋值当前节点,从当前节点开始查找,变量ph是当前节点的hash,变量dir是Comparable接口的比较结果变量pl当前节点的左节点,变量pr当前节点的右节点,变量q是右节点查找时候的返回值,如果找到了返回找到的节点
参数h是TreeNode的hash,而hash就是保持平衡二叉树的字段,通过它进行比较,小的放左边,大的放右边
参数k是要查找的节点的key
参数kc是要查找节点实现的key的运行时类型
final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
//当前对象
TreeNode<K,V> p = this;
do {
int ph, dir; K pk;
//当前对象的hash值,方向,键对象
TreeNode<K,V> pl = p.left, pr = p.right, q;//左右孩子及q:存储并返回找到的对象
//如果当前节点的hash值大于k的hash值,左孩子赋值给p,
//如果小于,右孩子赋值给p,
//如果相等,并且当前节点的键对象pk和k相等,返回当前节点。
if ((ph = p.hash) > h)
p = pl;
else if (ph < h)
p = pr;
else if ((pk = p.key) == k || (k != null && k.equals(pk)))
return p;
//如果左孩子为空,右孩子赋值给p
//如果右孩子为空,左孩子赋值给p
else if (pl == null)
p = pr;
else if (pr == null)
p = pl;
//如果左右孩子都不为空,通过key实现的comparable比较。comparableClassFor是获取k的运行时类型。
//compareComparables方法先判断,key与运行时kc是同类型,在通过调用k和kc实现的Comparable接口的compareTo进行比较
else if ((kc != null ||
(kc = comparableClassFor(k)) != null) &&
(dir = compareComparables(kc, k, pk)) != 0)
p = (dir < 0) ? pl : pr;
else if ((q = pr.find(h, k, kc)) != null)
return q;
//如果均不满足,右节点递归比较找到且返回,找不到就将左孩子赋值给p,进入下回循环在比较
else
p = pl;
} while (p != null);
return null;
}
//先找到根节点然后调用find()方法,parent如果为空,表示现在的节点是root
final TreeNode<K,V> getTreeNode(int h, Object k) {
return ((parent != null) ? root() : this).find(h, k, null);
}
final void treeify(Node<K,V>[] tab)双向链表变为红黑树
final Node<K,V> untreeify(HashMap<K,V> map)树转链表
/**
* Forms tree of the nodes linked from this node.
*/
final void treeify(Node<K,V>[] tab) {
//构建数的根节点
TreeNode<K,V> root = null;
//x指向当前节点,遍历链表
for (TreeNode<K,V> x = this, next; x != null; x = next) {
//下一个节点
//节点的左右节点均为空
next = (TreeNode<K,V>)x.next;
x.left = x.right = null;
//如果根节点为空
if (root == null) {
//当前节点的父节点赋值为空,红属性为false即此节点为黑,根节点指向当前节点
x.parent = null;
x.red = false;
root = x;
}
//如果存在根节点,取得当前链表节点的key、hash值
else {
K k = x.key;
int h = x.hash;
//定义key所属的class
Class<?> kc = null;
//从根节点开始遍历
for (TreeNode<K,V> p = root;;) {
int dir, ph;
K pk = p.key;
//如果当前节点hash值大于链表节点的hash值,当前链表节点指当前树节点的左侧
if ((ph = p.hash) > h)
dir = -1;
else if (ph < h)
//右侧
dir = 1;
//如果两节点key、hash值相等,进行comparable比较,若相等进行tieBreakOrder比较
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0)
dir = tieBreakOrder(k, pk);
//保存当前数节点
TreeNode<K,V> xp = p;
/*
* 如果dir <= 0 当前链表节点一定放置在当前树节点的左侧,
* 但不一定是该树节点的左孩子,也可能是左孩子的右孩子 或者 更深层次的节点。
* 如果dir > 0 当前链表节点一定放置在当前树节点的右侧,
* 但不一定是该树节点的右孩子,也可能是右孩子的左孩子 或者 更深层次的节点。
* 如果当前树节点不是叶子节点,那么最终会以当前树节点的左孩子或者右孩子 为 起始节点
* 再从 根节点遍历 处开始 重新寻找自己(当前链表节点)的位置
* 如果当前树节点就是叶子节点,那么根据dir的值,就可以把当前链表节点挂载到当前树节点的左或者右侧了。
* 挂载之后,还需要重新把树进行平衡。平衡之后,就可以针对下一个链表节点进行处理了。
*/
if ((p = (dir <= 0) ? p.left : p.right) == null) {
//当前链表的节点做当前树节点的子节点
x.parent = xp;
if (dir <= 0)
xp.left = x;
else
xp.right = x;
//重新平衡
root = balanceInsertion(root, x);
break;
}
}
}
}
moveRootToFront(tab, root);
}
/**
* Returns a list of non-TreeNodes replacing those linked from
* this node.
*/
final Node<K,V> untreeify(HashMap<K,V> map) {
Node<K,V> hd = null, tl = null;
for (Node<K,V> q = this; q != null; q = q.next) {
Node<K,V> p = map.replacementNode(q, null);
if (tl == null)
hd = p;
else
tl.next = p;
tl = p;
}
return hd;
}
final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab, int h, K k, V v) 插入数据、
final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab, boolean movable) 移除数据
/**
* Tree version of putVal.
*/
final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
int h, K k, V v) {
Class<?> kc = null;
boolean searched = false;
TreeNode<K,V> root = (parent != null) ? root() : this;
for (TreeNode<K,V> p = root;;) {
int dir, ph; K pk;
//比较hash值的大小,大于或者小于则查找子树,相等直接返回
if ((ph = p.hash) > h)
dir = -1;//左
else if (ph < h)
dir = 1;//右
else if ((pk = p.key) == k || (k != null && k.equals(pk)))
return p;
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0) {
if (!searched) {
TreeNode<K,V> q, ch;
searched = true;
if (((ch = p.left) != null &&
(q = ch.find(h, k, kc)) != null) ||
((ch = p.right) != null &&
(q = ch.find(h, k, kc)) != null))
return q;
}
dir = tieBreakOrder(k, pk);
}
//根据比较的hash值的大小的结果更新p为左孩子还是右孩子
TreeNode<K,V> xp = p;
if ((p = (dir <= 0) ? p.left : p.right) == null) {
Node<K,V> xpn = xp.next;
TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
if (dir <= 0)
xp.left = x;
else
xp.right = x;
xp.next = x;
x.parent = x.prev = xp;
if (xpn != null)
((TreeNode<K,V>)xpn).prev = x;
moveRootToFront(tab, balanceInsertion(root, x));
return null;
}
}
}
/**
* Removes the given node, that must be present before this call.
* This is messier than typical red-black deletion code because we
* cannot swap the contents of an interior node with a leaf
* successor that is pinned by "next" pointers that are accessible
* independently during traversal. So instead we swap the tree
* linkages. If the current tree appears to have too few nodes,
* the bin is converted back to a plain bin. (The test triggers
* somewhere between 2 and 6 nodes, depending on tree structure).
*/
final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
boolean movable) {
int n;
//tab为空,根节点为空,树的数量少转为链表,返回null,
if (tab == null || (n = tab.length) == 0)
return;
int index = (n - 1) & hash;
TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
if (pred == null)
tab[index] = first = succ;
else
pred.next = succ;
if (succ != null)
succ.prev = pred;
if (first == null)
return;
if (root.parent != null)
root = root.root();
if (root == null
|| (movable
&& (root.right == null
|| (rl = root.left) == null
|| rl.left == null))) {
tab[index] = first.untreeify(map); // too small
return;
}
TreeNode<K,V> p = this, pl = left, pr = right, replacement;
//寻找要替换的点
if (pl != null && pr != null) {
TreeNode<K,V> s = pr, sl;
while ((sl = s.left) != null) // find successor
s = sl;
boolean c = s.red; s.red = p.red; p.red = c; // swap colors
TreeNode<K,V> sr = s.right;
TreeNode<K,V> pp = p.parent;
if (s == pr) { // p was s's direct parent
p.parent = s;
s.right = p;
}
else {
TreeNode<K,V> sp = s.parent;
if ((p.parent = sp) != null) {
if (s == sp.left)
sp.left = p;
else
sp.right = p;
}
if ((s.right = pr) != null)
pr.parent = s;
}
p.left = null;
if ((p.right = sr) != null)
sr.parent = p;
if ((s.left = pl) != null)
pl.parent = s;
if ((s.parent = pp) == null)
root = s;
else if (p == pp.left)
pp.left = s;
else
pp.right = s;
if (sr != null)
replacement = sr;
else
replacement = p;
}
else if (pl != null)
replacement = pl;
else if (pr != null)
replacement = pr;
else
replacement = p;
//如果要移除的不是这个TreeNode,则替换当前节点的父节点或者左右节点
if (replacement != p) {
TreeNode<K,V> pp = replacement.parent = p.parent;
if (pp == null)
root = replacement;
else if (p == pp.left)
pp.left = replacement;
else
pp.right = replacement;
p.left = p.right = p.parent = null;
}
//如果是黑树就调用balanceDeletion方法实现平衡
TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);
//如果要移除得是当前TreeNode则从树中移除当前节点
if (replacement == p) { // detach
TreeNode<K,V> pp = p.parent;
p.parent = null;
if (pp != null) {
if (p == pp.left)
pp.left = null;
else if (p == pp.right)
pp.right = null;
}
}
if (movable)
moveRootToFront(tab, r);
}
final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit)将红黑树拆成两个链表,(扩容原因导致原本在一个数组元素下的Node节点分为高低位两部分)再根据链表长度决定树化或链表化
/**
* Splits nodes in a tree bin into lower and upper tree bins,
* or untreeifies if now too small. Called only from resize;
* see above discussion about split bits and indices.
*
* @param map the map
* @param tab the table for recording bin heads
* @param index the index of the table being split
* @param bit the bit of hash to split on
*/
final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
TreeNode<K,V> b = this;
//拆成两个链表
// Relink into lo and hi lists, preserving order
TreeNode<K,V> loHead = null, loTail = null;
TreeNode<K,V> hiHead = null, hiTail = null;
int lc = 0, hc = 0;
for (TreeNode<K,V> e = b, next; e != null; e = next) {
next = (TreeNode<K,V>)e.next;
e.next = null;
//当前节点hash值与bit(数值是扩容前的容量大小)位运算
if ((e.hash & bit) == 0) {
//0说明在低位树,即为原位置
if ((e.prev = loTail) == null)
loHead = e;
else
loTail.next = e;
loTail = e;
++lc;
}
else {
//同上,高位树
if ((e.prev = hiTail) == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
++hc;
}
}
//对高低位树处理,将数组节点指向树根节点或者链表首节点
if (loHead != null) {
//与非树化阈值比较
if (lc <= UNTREEIFY_THRESHOLD)
//转换成链表结构
tab[index] = loHead.untreeify(map);
else {
tab[index] = loHead;
//如果高位树为空
//表示节点全在低位树,不需要再进行树化(已树化)
if (hiHead != null) // (else is already treeified)
loHead.treeify(tab);
}
}
if (hiHead != null) {
if (hc <= UNTREEIFY_THRESHOLD)
tab[index + bit] = hiHead.untreeify(map);
else {
//设置高位树位置:原本位置+旧数组大小(bit)
tab[index + bit] = hiHead;
if (loHead != null)
hiHead.treeify(tab);
}
}
}