源码分析

TreeMap 是以 key 为排序的一个红黑树。 我们来看下他的一个节点

1
2
3
4
5
6
7
8
static final class TreeMapEntry<K,V> implements Map.Entry<K,V> {
K key;
V value;
TreeMapEntry<K,V> left;
TreeMapEntry<K,V> right;
TreeMapEntry<K,V> parent;
boolean color = BLACK;
}

光看节点信息结构就可以很清晰的看出来其是一个红黑树。 我们翻开 TreeMap 的源码去看它的成员变量的时候发现,很简单, 其实一个 size 记录数据的大小, root 一个根即可。

插入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public V put(K key, V value) {
TreeMapEntry<K,V> t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check

root = new TreeMapEntry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
TreeMapEntry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
TreeMapEntry<K,V> e = new TreeMapEntry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}

上面就是 put 的所有代码, 其实分析到现在我们看过了 HashMap, 其阅读还是比较简单的。 插入数据可以看到有几个分支

  • 如果当前一个数据都没有的话, 现在插入的数据就是 root 根。
  • 如果不是的话, 我们通过不管是自己定义的排序还是 key 默认的比较排序, 进行循环尝试找当前 node 的数据, 如果找到了, 那就直接更新数据, 如果没有找到, 可以看到已经找到了当前要插入位置的 parent 节点, 然后通过我们的比较器去在正确的位置插入新的数据。
  • fixAfterInsertion 更新处理红黑树。

查询数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public V get(Object key) {
TreeMapEntry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}

final TreeMapEntry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
TreeMapEntry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}

不过多分析了吧, 就是找到就返回, 没有找到就返回空。