继承关系
1.实现Serializable接口,即支持序列化。
2.TreeSet实现了Cloneable接口,意味着它能被克隆。
3.实现Iterable接口,即能用foreach使用迭代器遍历得到集合元素。
4.TreeSet实现了NavigableSet接口,意味着它支持一系列的导航方法。比如查找与指定目标最匹配项。
5.继承AbstractSet,AbstractSet实现set,所以它是一个Set集合,不包含满足element1.eauqals(element2)的元素树,
不重复,并且最多包含一个null。
基本属性
private transient NavigableMap<E,Object> m;
private static final Object PRESENT = new Object();
构造方法及初始化
1.使用NavigableMap的构造方法,底层是map
/**
* Constructs a set backed by the specified navigable map.
* 构造由指定的可导航映射支持的集合。
*/
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
2.默认构造函数。使用该构造函数,TreeSet中的元素按照自然排序进行排列。
底层使用的TreeMap
public TreeSet() {
this(new TreeMap<E,Object>());
}
3.传入comparator的构造方法
// 以定制排序方式创建一个新的 TreeMap,
// 根据该 TreeSet 创建一个 TreeSet,
// 使用该 TreeMap 的 key 来保存 Set 集合的元素
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
4.调用方式2构造器创建一个 TreeSet,底层以 TreeMap 保存集合元素
public TreeSet(Collection<? extends E> c) {
this();
//向 TreeSet 中添加 Collection 集合 c 里的所有元素
addAll(c);
}
5.调用方式3构造器创建一个 TreeSet
public TreeSet(SortedSet<E> s) {
this(s.comparator());
//向 TreeSet 中添加 SortedSet 集合 s 里的所有元素
addAll(s);
}
小结
TreeSet是基于TreeMap实现的。
TreeSet中的元素支持2种排序方式:自然排序或者根据创建TreeSet 时提供的 Comparator 进行排序。这取决于使用的构造方法。
TreeSet为基本操作(add、remove 和 contains)提供受保证的log(n)时间开销。
TreeSet是非同步的。 它的iterator方法返回的迭代器是fail-fast的。
常用方法
add
值都是同一个PRESENT(Object), 底层还是调用的map的put方法,这里会调用TreeMap的put 方法
如果不存在则添加,如果存在这样的元素则不添加
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
addAll
// 将集合c中的全部元素添加到TreeSet中
public boolean addAll(Collection<? extends E> c) {
// Use linear-time version if applicable
if (m.size()==0 && c.size() > 0 &&
c instanceof SortedSet &&
m instanceof TreeMap) {
SortedSet<? extends E> set = (SortedSet<? extends E>) c;
TreeMap<E,Object> map = (TreeMap<E, Object>) m;
Comparator<? super E> cc = (Comparator<? super E>) set.comparator();
Comparator<? super E> mc = map.comparator();
if (cc==mc || (cc != null && cc.equals(mc))) {
map.addAllForTreeSet(set, PRESENT);//还是调用TreeMap中的方法实现的
return true;
}
}
return super.addAll(c);
}
remove
由于之前添加的值都是PRESENT(Object),所以删除的时候
调用map 的删除方法,成功的返回值也会是PRESENT(Object),所以会是相等的。
返回ture,删除失败则不相等,返回false。
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
clear
调用map的clear方法,直接清除所有的键
public void clear() {
m.clear();
}
小结
还提供了一系列的方法,比如:
// 返回TreeSet的顺序排列的迭代器。
// TreeSet是TreeMap实现的,所以这里实际上时返回TreeMap的“键集”对应的迭代器
public Iterator<E> iterator() {
return m.navigableKeySet().iterator();
}
// 返回TreeSet的逆序排列的迭代器。
// 同上这里实际上时返回TreeMap的“键集”对应的迭代器
public Iterator<E> descendingIterator() {
return m.descendingKeySet().iterator();
}
总结
1.不能有重复的元素;
2.具有排序功能;
3.TreeSet中的元素必须实现Comparable接口并重写compareTo()方法,TreeSet判断元素是否重复 、以及确定元素的顺序 靠的都是这个方法;
4.对于java类库中定义的类,TreeSet可以直接对其进行存储,如String,Integer等,因为这些类已经实现了Comparable接口);
5.对于自定义类,如果不做适当的处理,TreeSet中只能存储一个该类型的对象实例,否则无法判断是否重复。
6.依赖于TreeMap,底层是TreeMap。
7.相对HashSet,TreeSet的优势是有序,劣势是相对读取慢。
根据不同的场景选择不同的集合。
TreeSet 和 HashSet比较
相同点:
都是唯一不重复的Set集合。
不同点:
底层结构
HashSet是用Hash表来存储数据,而TreeSet是用二叉平衡树来存储数据。
功能上
由于TreeSet是有序的Set,可以使用SortedSet。接口的first()、last()等方法。
但由于要排序,势必要影响速度。
所以,在不需要顺序的情况下,使用HashSet,这方面使用Hash表存储数据的HashSet在速度上更胜一筹。
如果需要顺序则使用TreeSet。
TreeSet 和 HashMap比较
相同点
1.TreeMap和TreeSet都是有序的集合。
2.TreeMap和TreeSet都是非同步集合,因此他们不能在多线程之间共享,不过可以使用方法Collections.synchroinzedMap()来实现同步。
3.运行速度都要比Hash集合慢,他们内部对元素的操作时间复杂度为O(logN),而HashMap/HashSet则为O(1)。
不同点
1.实现的接口不同TreeSet实现Set接口,而TreeMap实现Map接口。
2.TreeSet只存储一个对象,而TreeMap存储两个对象Key和Value(仅仅key对象有序)。
3.TreeSet中不能有重复对象,而TreeMap中可以存在。
写在后面的话
love all, trust a few, do wrong to none .
下集预告
提到分布式,就不可避免的会考虑到分布式锁,而它的实现方式就显得尤为重要。
所以下期就是分布式锁的实现方式。