TreeSet 继承关系
类文档解读
老规矩,先通过 TreeSet 的类文档了解一下能得到哪些信息。
- TreeSet 是 JDK 1.2 提供的基于 TreeMap 的 NavigableSet 实现。
- TreeSet 支持元素的自然排序和按照在创建时指定的 Comparator 比较器进行排序。
- TreeSet 的基本操作(add、remove 和 contains)的时间复杂度是 log(n) 。
- TreeSet 是非线程安全的。
- TreeSet 的迭代器是 fail-fast 策略的。
TreeSet API
成员变量
// 存储数据的底层数据结构
private transient NavigableMap<E,Object> m;
// 由于 TreeSet 只需要使用 Key 进行存储,因此 Value 存储的是一个虚拟值
private static final Object PRESENT = new Object();
构造方法
TreeSet 底层使用的是 NavigableMap 存储数据,如果没有指定具体是 NavigableMap 的哪个实现类则默认使用 TreeMap 作为底层存储数据的结构。
/**
* 通过指定的 NavigableMap 创建实例
*/
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
/**
* 使用 TreeMap 创建一个空的 TreeSet,使用自然排序,
* 添加的元素需要实现 Comparable 接口,即是可比较的
*/
public TreeSet() {
this(new TreeMap<E,Object>());
}
/**
* 指定比较器,如果比较器是 null 将使用自然排序
*/
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
}
其他API
TreeSet 对元素的操作基本都是调用 NavigableMap 的方法进行操作。
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
public boolean contains(Object o) {
return m.containsKey(o);
}
public E pollFirst() {
Map.Entry<E,?> e = m.pollFirstEntry();
return (e == null) ? null : e.getKey();
}
总结
- TreeSet 里添加的元素必须是同一类型的。
- 当向 TreeSet 内添加对象时,可以有两种排序方法:
- 自然排序,如 String、包装类默认按照从小到大的顺序遍历。
- 定制排序。
自然排序
TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列。如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。实现 Comparable 的类必须重写 compareTo(Object obj) 方法,两个对象通过 compareTo(Object obj) 方法的返回值来比较大小。
当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 时,应保证与 compareTo(Object obj) 方法有一致的结果:如果两个对象通过 equals() 方法比较返回 true,则通过 compareTo(Object obj) 方法比较应返回 0,要求 equals() 方法和 hashCode() 方法和 compareTo() 方法保持一致。
定制排序
TreeSet 的自然排序是根据集合元素的大小,进行元素升序排列。如果需要定制排序,比如降序排列,可借助 Comparator 接口的帮助。需要重写 compare(T o1,T o2) 方法。利用 int compare(T o1,T o2) 方法,比较 o1 和 o2 的大小:如果方法返回正整数,则表示 o1 大于 o2;如果返回 0 表示相等;返回负整数 表示 o1 小于 o2。要实现定制排序,需要将实现 Comparator 接口的实例作为形参传递给 TreeSet 的构造器。此时仍然只能向 TreeSet 中添加类型相同的对象否则发生 ClassCastException 异常。使用定制排序判断两个元素相等的标准是:通过 Comparator 比较两个元素返回了 0,要求 equals() 方法和 hashCode() 方法和 compareTo() 方法保持一致。