package java.util;
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable{
}
public interface NavigableMap<K,V> extends SortedMap<K,V>{}
TreeMap继承AbstractMap,实现NavigableMap、Cloneable、Serializable三个接口。其中AbstractMap表明TreeMap为一个Map即支持key-value的集合, NavigableMap则意味着它支持一系列的导航方法,具备针对给定搜索目标返回最接近匹配项的导航方法 。
TreeMap中同时也包含了如下几个重要的属性:
//比较器,因为TreeMap是有序的,通过comparator接口我们可以对TreeMap的内部排序进行精密的控制
private final Comparator super K> comparator;
//TreeMap红-黑节点,为TreeMap的内部类
private transient Entryroot = null;
//容器大小
private transient int size = 0;
//TreeMap修改次数
private transient int modCount = 0;
//红黑树的节点颜色–红色
private static final boolean RED = false;
//红黑树的节点颜色–黑色
private static final boolean BLACK = true;
对于实体节点Entry是TreeMap的内部类,它有几个重要的属性:
//键
K key;
//值
V value;
//左孩子
Entryleft = null;
//右孩子
Entryright = null;
//父亲
Entryparent;
//颜色
boolean color = BLACK;
关于红黑树的实现可以搜索一些相关资料,我觉得参考资料3就不错,博主就不赘述了。
Map<Integer,Integer> map = new TreeMap<>();
map.put(1, null);
map.put(10, 1);
map.put(3, 2);
map.put(2, 3);
// map.put(null, 3);
for(Entry<Integer, Integer> entry:map.entrySet())
{
System.out.println(entry.getKey()+":"+entry.getValue());
}
输出结果:
1:null
2:3
3:2
10:1
也可以采用自定义的类,引用《Comparable与Comparator浅析》中的Person1举例:
public class Person1 implements Comparable<Person1>
{
private int age;
private String name;
public Person1(String name, int age)
{
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person1 o)
{
return this.age-o.age;
}
@Override
public String toString()
{
return name+":"+age;
}
}
测试代码:
Map<Person1,Integer> map = new TreeMap<>();
Person1 person1 = new Person1("zzh",18);
Person1 person2 = new Person1("jj",17);
Person1 person3 = new Person1("qq",19);
map.put(person1, 1);
map.put(person2, 2);
map.put(person3, 3);
for(Entry<Person1, Integer> entry:map.entrySet())
{
System.out.println(entry.getKey()+":"+entry.getValue());
}
测试结果:
jj:17:2
zzh:18:1
qq:19:3
只要自定义键的类实现了Comparable接口就可以使用TreeMap的排序功能,也可以通过Comparator接口实现(关于Comparable和Comparator的区别可以翻看《Comparable与Comparator浅析》),如下:
首先引用类Person2:
public final class Person2
{
private int age;
private String name;
public Person2(String name, int age)
{
this.name = name;
this.age = age;
}
@Override
public String toString()
{
return name+":"+age;
}
//getter and setter方法省略....
}
测试代码:
Map map2 = new TreeMap<>(new Comparator(){
@Override
public int compare(Person2 o1, Person2 o2)
{
if(o1 == null || o2 == null)
return 0;
return o1.getAge()-o2.getAge();
}
});
Person2 p1 = new Person2("zzh",18);
Person2 p2 = new Person2("jj",17);
Person2 p3 = new Person2("qq",19);
map2.put(p1, 1);
map2.put(p2, 2);
map2.put(p3, 3);
for(Entry entry:map2.entrySet())
{
System.out.println(entry.getKey()+":"+entry.getValue());
}
输出结果:
jj:17:2
zzh:18:1
qq:19:3
可以看到Person2中并没有实现Comparable接口,但是想要和Person1一样能够和TreeMap合作,只需要在创建TreeMap的构造函数中声明一个Comparator接口的实现,譬如上面的例子所示。
3. 由所有此类的“collection 视图方法”所返回的迭代器都是快速失败的。
这点和HashMap一样,所谓快速失败就是在并发集合中,其进行迭代操作时,若有其他线程对其结构性的修改,这是迭代器会立马感知到,并且立刻抛出ConcurrentModificationException异常,而不是等待迭代完成之后才告诉你已经出错。注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。 快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。 因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。
4. 和HashMap一样,如果插入重复的元素,后面的元素会覆盖前面的。
5. 键不可以为null(如果比较器对null做了处理,就可以为null),但是值可以为null。
如上面的案例中,加入:
Person2 p4 = new Person2(null,19);
map2.put(p4, 4);
在打印map2的时候就不会报错。
6. TreeMap对containsKey、get、put 和 remove 操作提供了保证的 log(n) 时间开销。
TreeMap提供了很多方法方便大小使用,譬如containsKey, get, put,remove,entrySet等Map通用的方法,也包括fisrtEntry, firstKey, cellingKey, lowerKey等方法,由于篇幅较大,不便赘述,使用前最好翻看一下API或者源码熟悉一下。
参考资料
1. 《Comparable与Comparator浅析》
2. 《Java中HashMap和TreeMap的区别深入理解》
3. 《Java提高篇(二七)—–TreeMap》