1. putTreeVal
这个方法主要是,当hashMap put 一个新的元素时,发现它要插入的数组的索引位置上,已经是一个红黑树结构的节点时,就会调用这个方法对它进行插入或者寻找,如果插入成功返回null,否则返回跟当前插入元素k 相同的元素。
/**
* map 当前节点所在的HashMap对象
* tab 当前HashMap对象的元素数组
* h 指定key的hash值
* k 指定key
* v 指定key上要写入的值
*/
final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
int h, K k, V v) {
// 记录k的class类型
Class<?> kc = null;
// 标识符: 表示是否已经遍历过一次树
boolean searched = false;
// 返回当前节点的根节点
TreeNode<K,V> root = (parent != null) ? root() : this;
// 从根节点遍历,无终止条件,只能内部结束遍历
for (TreeNode<K,V> p = root;;) {
// dir : 插入的方向 -1 左,1 右;ph:节点p的hash值; pk:节点p的key
int dir, ph; K pk;
// 如果p的hash值大于要插入的节点的hash值,则dir = -1,表示该节点会被插入p的左边
if ((ph = p.hash) > h)
dir = -1;
// 如果p的hash值小于要插入的节点的hash值,则dir = 1,表示该节点会被插入p的右边
else if (ph < h)
dir = 1;
// 如果通过 == 比较或者 equals方法(可以重写)比较p和要插入节点的key 返回true
else if ((pk = p.key) == k || (k != null && k.equals(pk)))
// 直接返回p,外层会判断当前插入的值,是否覆盖p的值
return p;
// 这里判断 (kc == null 且 k没有实现 Comparable 接口) 或者 compareComparables(kc, k, pk) == 0
// 这两个方法详解 见下面3.
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0) {
//走到这里说明:指定key没有实现comparable接口 或者 实现了comparable接口并且和当前节点的键对象比较之后相等
/*
* searched 标识是否已经对比过当前节点的左右子节点了
* 如果还没有遍历过,那么就递归遍历对比,看是否能够得到那个键对象equals相等的的节点
* 如果得到了键的equals相等的的节点就返回
* 如果还是没有键的equals相等的节点,那说明应该创建一个新节点了
*/
// 判断是否已经遍历过,如果没有则进入
if (!searched) {
TreeNode<K,V> q, ch;
// 把 searched 置为true
searched = true;
// 这里先从左子节点查询 如未找到在从右子节点找,最终返回 与指定key相等的节点
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);
}
TreeNode<K,V> xp = p;
// 当 dir <= 0时,表示要插入左边,把p.left赋给 p ,否则表示插入右边,把p.right 赋给p
// 当p == null(这里是修改后的p) 时,说明此时左/右子节点为null 可以直接插入,否则还要继续遍历
if ((p = (dir <= 0) ? p.left : p.right) == null) {
// 这里是可以插入的情况
// xpn : xp节点的next节点
Node<K,V> xpn = xp.next;
// 创建一个新的节点,并把它的next 设为 xpn
TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
// 如果 dir <= 0
if (dir <= 0)
// 把x设置为xp的左子节点
xp.left = x;
// 否则把x设置为 xp的右子节点
else
xp.right = x;
// 把xp.next设为 x
xp.next = x;
// 把 x的前置节点和父节点都设为 xp
x.parent = x.prev = xp;
// 如果 xpn 不为 null 则把它的 前置节点设为x
if (xpn != null)
((TreeNode<K,V>)xpn).prev = x;
// moveRootToFront : 返回根节点,保证它在最前面
// balanceInsertion: 平衡红黑树,使其满足红黑树的特性
// 详解见下方链接
moveRootToFront(tab, balanceInsertion(root, x));
return null;
}
}
}
2. root()
/**
* 返回当前节点的根节点
*/
final TreeNode<K,V> root() {
for (TreeNode<K,V> r = this, p;;) {
if ((p = r.parent) == null)
return r;
r = p;
}
}
3.comparableClassFor(k)
/**
* 如果当前类未实现 Comparable 接口返回null
* Returns x's Class if it is of the form "class C implements
* Comparable<C>", else null.
*/
static Class<?> comparableClassFor(Object x) {
if (x instanceof Comparable) {
Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
if ((c = x.getClass()) == String.class) // 如果x是个字符串对象
return c; // 返回String.class
/*
* 为什么如果x是个字符串就直接返回c了呢 ? 因为String 实现了 Comparable 接口
*/
// 如果 c 不是字符串类,获取c直接实现的接口(如果是泛型接口则附带泛型信息)
if ((ts = c.getGenericInterfaces()) != null) {
for (int i = 0; i < ts.length; ++i) { // 遍历接口数组
// 如果当前接口t是个泛型接口
// 如果该泛型接口t的原始类型p 是 Comparable 接口
// 如果该Comparable接口p只定义了一个泛型参数
// 如果这一个泛型参数的类型就是c,那么返回c
if (((t = ts[i]) instanceof ParameterizedType) &&
((p = (ParameterizedType)t).getRawType() ==
Comparable.class) &&
(as = p.getActualTypeArguments()) != null &&
as.length == 1 && as[0] == c) // type arg is c
return c;
}
// 上面for循环的目的就是为了看看x的class是否 implements Comparable<x的class>
}
}
return null; // 如果c并没有实现 Comparable<c> 那么返回空
}
4.compareComparables()
/**
* Returns k.compareTo(x) if x matches kc (k's screened comparable
* class), else 0.
*/
@SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
static int compareComparables(Class<?> kc, Object k, Object x) {
// 这里 kc : 对应前面插入节点的key的类型, k : 对应前面插入节点的key ,X:当前遍历节点的key
// 当 x == null或者 x.getClass() != kc 返回0,否则返回 (Comparable)k).compareTo(x)
return (x == null || x.getClass() != kc ? 0 :
((Comparable)k).compareTo(x));
}