TreeSet 是sortedSet的唯一實現類,正如SortedSet名字暗示,TreeSet可以讓集合元素處在排好序的狀態。
與HashSet相比,TreeSet還額外提供了以下的方法(列出來,混個臉熟:)
SortedSet subSet(Object fromElement,Object toElement) :返回這個Set的子集合,范圍從fromElement(包含)到toElement(不包含)
SortedSet headSet(Object toElement):返回這個Set的子集合,范圍小於到toElement的子集合
SortedSet tailSet(Object fromElement):返回這個Set的子集合,范圍大於或等於到fromElement的子集合
Object first(): 返回這個Set第一個元素
Object last():返回這個Set最后一個元素
Object lower(Object e):返回小於指定元素的集合里最大的那個元素
Object higher(Object e):返回大於指定元素的集合里最小的那個元素
【以上參考元素都不需要是集合里的】
總結一下,最后四個方法就是找到集合里的第一個,前一個,后一個,最后一個元素。同時前三個就是返回該集合的符合條件的子集合。
package Test01; import java.util.TreeSet; public class TestTreeSet { public static void main(String[] args) { TreeSet num =new TreeSet(); num.add(2);
num.add(-2); num.add(10); num.add(9); System.out.println(num); //看出:不是按照添加的順序來,是數字由小到大排序 System.out.println(num.first()); //看出:數字由小到大排序的第一個 System.out.println("9到12 之間的"+num.subSet(9, 12)); System.out.println("比8小的"+num.headSet(8)); System.out.println("比8大的"+num.tailSet(8)); } }
與hashset采用hash算法決定元素的存儲位置,TreeSet采用紅黑樹的數據結構(待跟進)來存儲集合元素。那么他的排序規則是怎么的呢?
自然排序(默認情況)。
調用TreeSet的無參的構造器,並實現Comparable接口,實現里的 compareTo(Object obj)方法,來比較集合元素的大小,然后按照compareTo里的排序。
該種方法注意:
向TreeSet里添加元素時,只有第一個無須實現Comparable接口,后面的必須實現。(第二個及后面的會調用compareTo方法,與集合里的其他元素比較,要求了比較的兩個元素都是一個類的實例,否則會ClassCastException)
package Test01; import java.util.TreeSet; public class Foo implements Comparable{ int num; public Foo(int num) { this.num =num; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } @Override public String toString() { // TODO Auto-generated method stub return "foo:"+this.getNum(); } @Override public int compareTo(Object obj) { // TODO Auto-generated method stub if(obj instanceof Foo) { Foo f = (Foo) obj; if(this.num > f.getNum()) { return 1; } if(this.num == f.getNum()) { return 0; } else return -1; } else return 0; } public static void main(String[] args) { TreeSet<Foo> test = new TreeSet<>(); test.add(new Foo(8)); test.add(new Foo(3)); System.out.println(test); } }
下面的一些常用的類已經實現了Comparable接口,提供了比較大小的標准:
BigDecimal
character
Boolean
String
Date Time
對於TreeSet集合來說,判斷兩個對象是否相等的唯一標准 是compareTo(Object obj)返回0,是0 就相等,不是0就不等。就不會讓相等的對象進入集合。
舉例
(正確的結果)能夠插入兩個compare 不等於0但是equals為true的對象
package Test01; import java.util.Comparator; import java.util.TreeSet; public class Comp implements Comparator<Foo>{ @Override public int compare(Foo o1, Foo o2) { return 1; } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub return true; } public static void main(String[] args) { TreeSet<Foo> t = new TreeSet<>(new Comp()); Foo f = new Foo(0); t.add(f); t.add(f); System.out.println(t); t.first().num =9; System.out.println(t); } }
留意下注釋的差別,(問題已解決)
package Test01; import java.util.TreeSet; public class Test implements Comparable{ int num; public Test(int num) { this.num=num; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub return true; } @Override public int compareTo(Object o) { // TODO Auto-generated method stub return 1; } public static void main(String[] args) { TreeSet t = new TreeSet(); Test f = new Test(0); t.add(f); System.out.println("會把同一個對象但是compareTo返回1添加進TreeSet嗎?"+ t.add(f)); //equals不是評價對象相等的標准,compareTo返回0才相等。返回true System.out.println(t); ((Test)(t.first())).num=9; //修改第一個元素,下面一行發現最后一個元素也被改成了9 System.out.println( ((Test)(t.last())).num); } }
由正確的結果注意:TreeSet也是Set,equals結果注意保持和compareTo結果一致。因為如果compareTo 等於0,但是equals發現false,就和Set沖突。
和hashset同樣,討論下,可變對象插入刪除問題(留意注釋部分)
package Test01; import java.util.Iterator; import java.util.TreeSet; class mutClass implements Comparable{ public int count; public mutClass(int count) { this.count =count; } public boolean equals(Object obj) { if(this == obj) { return true; } if(obj != null && obj.getClass() == mutClass.class) { mutClass m =(mutClass) obj; return this.count == m.count; } return false; } public int hashcode() { return this.count; } public String toString() { return "試試mutClass[count=" + count + "]"; } @Override public int compareTo(Object o) { // TODO Auto-generated method stub mutClass m = (mutClass) o; return count>m.count?1 :count<m.count?-1 :0; } } public class TestTreeSet { @SuppressWarnings("unchecked") public static void main(String[] args){ TreeSet testHashSet =new TreeSet(); mutClass a = new mutClass(3); mutClass b = new mutClass(1); mutClass c = new mutClass(-9); mutClass d = new mutClass(9); testHashSet.add(a); testHashSet.add(b); testHashSet.add(c); testHashSet.add(d); System.out.println("第一次"+testHashSet); ((mutClass)testHashSet.first()).count =20; System.out.println("第二次"+testHashSet); //修改可變對象的實例變量,不會調整順序 ((mutClass)testHashSet.last()).count =1; //修改可變對象的實例變量,不會調整順序,且可能出現重復對象的情況 System.out.println("第三次"+testHashSet); System.out.println(testHashSet.remove(new mutClass(1))); //刪除實例變量被修改的元素,應該刪除失敗,但是我刪除成功了? System.out.println("第四次"+testHashSet); } }
定制排序。
自己寫個比較器的類,傳入TreeSet的有參數的構造器,這樣往集合里add元素就能按照定制的順序排序了。
package Test01; import java.util.Comparator; import java.util.TreeSet; public class Comp implements Comparator<Foo>{ @Override public int compare(Foo o1, Foo o2) { // TODO Auto-generated method stub if(o1.getNum()>o2.getNum()) { return 1; } if (o1.getNum() == o2.getNum()) { return 0; } else return -1; } public static void main(String[] args) { TreeSet<Foo> t = new TreeSet<>(new Comp()); t.add(new Foo(0)); t.add(new Foo(-9)); System.out.println(t); } }