TreeSet是Set接口的子接口SortedSet的唯一的實現類,TreeSet對其中的元素進行排序。
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable
可以看到TreeSet繼承了AbstractSet並實現了NavigableSet、Cloneable和Serializable等接口,其中NavigableSet接口是基於TreeMap實現的,他需要依賴元素的自然排序或者傳入一個定製的comparator比較器,這樣才能實現元素之間的比較並對元素進行排序,如果一個類並沒有實現Comparable接口並重寫comparaTo()方法,那麼在添加到TreeSet時會拋出java.langClassCastException。
1、TreeSet和TreeMap的關係
TreeSet是基於TreeMap實現的,而TreeMap是基於紅黑樹的數據結構實現的,也就是自平衡的排序二叉樹,那麼TreeSet也是基於紅黑樹的樹結構實現的,通過TreeSet的構造方法就可以看出,TreeSet就是特殊的TreeMap,而且TreeSet中很多方法都是基於TreeMap中的方法實現的。
TreeSet的構造方法: private transient NavigableMap<E,Object> m; //使用一個可序列化的NavigableMap來實現TreeSet
// 使用一個特定的不可更改的Object來作爲TreeMap的value
private static final Object PRESENT = new Object();
//構造器1,直接傳入一個NavigableMap來實現TreeSet
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
//構造器2
//傳入一個TreeMap來實現TreeSet,根據自然排序來實現元素間的比較和排序,因此插入的元素必須實現Comparabel接口並實現comparaTo()方法
//並且傳入的元素的compareTo()方法的結果必須是一致的,否則會拋出ClassCastException
public TreeSet() {
this(new TreeMap<E,Object>());
}
//構造器3
//傳入一個構造器,使用構造器2,並向TreeMap中傳入比較器Comparator,在添加元素的時候,使用Comparator接口的Compara()方法對元素進行比較
//和排序
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
//構造器4
//使用構造器1,並把Collection c中的元素添加到TreeSet中
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
//利用構造器3,將排序集的比較器傳入,並將排序集s中的元素添加到TreeSet中
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
從TreeSet的構造函數中可以看出,TreeSet就是value爲不可變的Object對象的TreeMap。
此外,TreeSet中國的很多函數都是基於TreeMap中的函數實現的,例如:
迭代器:
public Iterator<E> iterator() {
return m.navigableKeySet().iterator();
}
isEmpty()方法:
public boolean isEmpty() {
return m.isEmpty();
}
還有很多方法都是這樣基於TreeMap實現的,具體可以看TreeSet的源碼。
2、元素的排序方式
TreeSet的元素排序的兩種方式:自然排序(Comparable接口)和定製比較器(comparator接口)
自然排序:對於實現了comparable接口的對象,在被添加進TreeSet的時候,TreeSet會把該對象提升爲Comparable類型,並調用comparaTo()方法,根據方法的返回值進行排序。
定製比較器comparator:在創建TreeSet的時候,可以傳入定製的比較器Comparator,如果傳入了Comparator的子類對象,Tadd()方法的內部會自動調用Comparator接口中的compare()方法,調用的對象是compare方法的第一個參數,集合中的對象是compare方法的第二個參數。
*TreeSet構造函數什麼都不傳, 默認按照類中Comparable的順序(沒有就報錯ClassCastException),TreeSet如果傳入Comparator, 就優先按照Comparator的順序比較
comparable和comparator的區別:
Comparable:此接口強行對實現它的每個類的對象進行整體排序。這種排序被稱爲類的自然排序,類的 compareTo 方法被稱爲它的自然比較方法。
他們都是用來實現集合中元素的比較、排序的,只是comparable是在集合內部定義的方法實現的排序,而comparator是在集合外部實現的排序。
comparator位於包java.util下,而comparable位於包java.lang下。