TreeMap是用红黑树实现的,不妨按照之前《红黑树》的那一篇笔记的流程来分析,这里采用的是JDK1.8.0_91对应的源码。
初始化
注释写到:“Node in the Tree. Doubles as a means to pass key-value pairs back to user (see Map.Entry).”之前某篇我提到过JDK8在部分源码中已经使用Node替代Entry,这里仍然使用的是Entry:
|
|
和以往不同的是,这里增加了parent字段,Entry是静态类。
Put
先看看源码中put()是怎么实现的:
|
|
这段代码一开始采用了compare(key, key)
的比较,其实不难理解:如果root为null的话,构造root的时候(也就是new一个新的Entry)天然缺少类型检查,比如你可以不强迫新的Entry键值为类型K和V,而当root存在的时候,put()的元素都是会和父节点比较的,这样就隐式进行过类型(包括null)检查了。这里compare()是内部实现的一个final方法:
|
|
comparator不为null就用Comparator比较,为null就用Comparable比较。Comparator和Comparable的区别我在某篇中提到过,前者是外部比较器,后者可以视为内部比较器,通过重写外部比较器,可以方便更改比较规则。
modCount++的意涵在之前某源码摘要中也提到过,这里和那篇中的用法一样。fixAfterInsertion(e)
用来插入后再平衡,基本原理见之前涉及红黑树的那篇。
应用
TreeMap的构造函数如下:
|
|
可见,默认采用Comparable,Comparator实例可以作为实参更改排序规则。
Collections的一个静态方法reverseComparator()返回逆序比较器:
|
|
所以通过给构造器传入该方法,遍历的时候可以得到逆序结果。
再者,TreeMap的排序默认是高位优先(具体可见《算法(第4版)》)的。所以排序的内容如果有自己特定的逻辑规则,也应该自行实现Comparator。
小结
较之HashMap,TreeMap很稳,不然在Java8的HashMap源码中,就不会将某些特定情况转换成TreeMap来实现,基本操作的时间复杂度和红黑树一样。