日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Java集合框架總結(jié):TreeSet類的排序問題

TreeSet支持兩種排序方法:自然排序和定制排序。TreeSet默認(rèn)采用自然排序。

1、自然排序

TreeSet會調(diào)用集合元素的compareTo(Object obj)方法來比較元素之間大小關(guān)系,然后將集合元素按升序排列,這種方式就是自然排序。(比較的前提:兩個(gè)對象的類型相同)。

java提供了一個(gè)Comparable接口,該接口里定義了一個(gè)compareTo(Object obj)方法,該方法返回一個(gè)整數(shù)值,實(shí)現(xiàn)該接口的類必須實(shí)現(xiàn)該方法,實(shí)現(xiàn)了該接口的類的對象就可以比較大小。當(dāng)一個(gè)對象調(diào)用該方法與另一個(gè)對象進(jìn)行比較,例如obj1.comparTo(obj2),如果該方法返回0,則表明這兩個(gè)對象相等;如果返回一個(gè)正整數(shù),則表明obj1大于obj2;如果該方法返回一個(gè)負(fù)整數(shù),則表明obj1小于obj2.

java常用類實(shí)現(xiàn)Comparable接口,并提供了比較大小的標(biāo)準(zhǔn)。實(shí)現(xiàn)Comparable接口的常用類:

  • BigDecimal、BigIneger以及所有數(shù)值型對應(yīng)包裝類:按它們對應(yīng)的數(shù)值的大小進(jìn)行比較。
  • Character:按字符的UNICODE值進(jìn)行比較。
  • Boolean:true對應(yīng)的包裝類實(shí)例大于false對應(yīng)的包裝類實(shí)例。
  • String:按字符串中字符的UNICODE值進(jìn)行比較。
  • Date、Time:后面的時(shí)間、日期比前面的時(shí)間、日期大。

如果試圖把一個(gè)對象添加進(jìn)TreeSet時(shí),則該對象的類必須實(shí)現(xiàn)Comparable接口。

如下程序則會報(bào)錯:

 
 
 
  1. class Err  
  2. {  
  3. }  
  4. public class TestTreeSetError  
  5. {  
  6. public static void main(String[] args)  
  7. {  
  8. TreeSet ts = new TreeSet();  
  9. //向TreeSet集合中添加兩個(gè)Err對象  
  10. ts.add(new Err());  
  11. ts.add(new Err());  
  12. }  
  13. }  
  14.  

說明:

上面程序試圖向TreeSet集合中添加2個(gè)Err對象,添加第一個(gè)對象時(shí),TreeSet里沒有任何元素,所以沒有問題;當(dāng)添加第二個(gè)Err對象時(shí),TreeSet就會調(diào)用該對象的compareTo(Object obj)方法與集合中其他元素進(jìn)行比較——如果對應(yīng)的類沒有實(shí)現(xiàn)Comparable接口,則會引發(fā)ClassCastException異常。而且當(dāng)試圖從TreeSet中取出元素第一個(gè)元素時(shí),依然會引發(fā)ClassCastException異常。

當(dāng)采用compareTo(Object obj)方法比較對象時(shí),都需要將被比較對象obj強(qiáng)制類型轉(zhuǎn)換成相同類型,因?yàn)橹挥邢嗤惖膬蓚€(gè)實(shí)例才能比較大小。即向TreeSet中添加的應(yīng)該是同一個(gè)類的對象,否則會引發(fā)ClassCastException異常。例如,當(dāng)向TreeSet中添加一個(gè)字符串對象,這個(gè)操作完全正常。當(dāng)添加第二個(gè)Date對象時(shí),TreeSet就好調(diào)用該對象的compareTo(Object obj)方法與集合中其他元素進(jìn)行比較,則此時(shí)程序會引發(fā)異常。

在實(shí)際編程中,程序員可以定義自己的類向TreeSet中添加多種類型的對象,前提是用戶自定義類實(shí)現(xiàn)了Comparable接口,實(shí)現(xiàn)該接口時(shí)在實(shí)現(xiàn)compareTo(Object obj)方法時(shí)沒有進(jìn)行強(qiáng)制類型轉(zhuǎn)換。但當(dāng)操作TreeSet里的集合數(shù)據(jù)時(shí),不同類型的元素依然會發(fā)生ClassCastExceptio異常。(認(rèn)真閱讀下就會明白)

當(dāng)把一個(gè)對象加入TreeSet集合中時(shí),TreeSet調(diào)用該對象的compareTo(Object obj)方法與容器中的其他對象比較大小,然后根據(jù)紅黑樹算法決定它的存儲位置。如果兩個(gè)對象通過compareTo(Object obj)比較相等,TreeSet即認(rèn)為它們存儲同一位置。

對于TreeSet集合而言,它判斷兩個(gè)對象不相等的標(biāo)準(zhǔn)是:兩個(gè)對象通過equals方法比較返回false,或通過compareTo(Object obj)比較沒有返回0——即使兩個(gè)對象時(shí)同一個(gè)對象,TreeSet也會把它們當(dāng)成兩個(gè)對象進(jìn)行處理。

如下程序所示:

 
 
 
  1. //Z類,重寫了equals方法,總是返回false,  
  2. //重寫了compareTo(Object obj)方法,總是返回正整數(shù)  
  3. class Z implements Comparable  
  4. {  
  5. int age;  
  6. public Z(int age)  
  7. {  
  8. this.age = age;  
  9. }  
  10. public boolean equals(Object obj)  
  11. {  
  12. return false;  
  13. }  
  14. public int compareTo(Object obj)  
  15. {  
  16. return 1;  
  17. }  
  18. }  
  19. public class TestTreeSet  
  20. {  
  21. public static void main(String[] args)  
  22. {  
  23. TreeSet set = new TreeSet();  
  24. Z z1 = new Z(6);  
  25. set.add(z1);  
  26. System.out.println(set.add(z1));  
  27. //下面輸出set集合,將看到有2個(gè)元素  
  28. System.out.println(set);  
  29. //修改set集合的第一個(gè)元素的age屬性  
  30. ((Z)(set.first())).age = 9;  
  31. //輸出set集合的最后一個(gè)元素的age屬性,將看到也變成了9  
  32. System.out.println(((Z)(set.last())).age);  
  33. }  
  34. }  

程序運(yùn)行結(jié)果:

true 
[TreeSet.Z@1fb8ee3, TreeSet.Z@1fb8ee3] 
9

說明:

程序中把同一個(gè)對象添加了兩次,因?yàn)閦1對象的equals()方法總是返回false,而且compareTo(Object obj)方法總是返回1。這樣TreeSet會認(rèn)為z1對象和它自己也不相同,因此TreeSet中添加兩個(gè)z1對象。而TreeSet對象保存的兩個(gè)元素實(shí)際上是同一個(gè)元素。所以當(dāng)修改TreeSet集合里第一個(gè)元素的age屬性后,該TreeSet集合里最后一個(gè)元素的age屬性也隨之改變了。

總結(jié):當(dāng)需要把一個(gè)對象放入TreeSet中時(shí),重寫該對象對應(yīng)類的equals()方法時(shí),應(yīng)保證該方法與compareTo(Object obj)方法有一致結(jié)果,其規(guī)則是:如果兩個(gè)對象通過equals方法比較返回true時(shí),這兩個(gè)對象通過compareTo(Object obj)方法比較應(yīng)返回0。

如果兩個(gè)對象通過equals方法比較返回true,但這兩個(gè)對象通過compareTo(Object obj)方法比較不返回0時(shí),這將導(dǎo)致TreeSet將會把這兩個(gè)對象保存在不同位置,從而兩個(gè)對象都可以添加成功,這與Set集合的規(guī)則有點(diǎn)出入。

如果兩個(gè)對象通過compareTo(Object obj)方法比較返回0時(shí),但它們通過equals方法比較返回false時(shí)將更麻煩:因?yàn)閮蓚€(gè)對象通過compareTo(Object obj)方法比較相等,TreeSet將試圖把它們保存在同一個(gè)位置,但實(shí)際上又不行(否則將只剩下一個(gè)對象),所以處理起來比較麻煩。

如果向TreeSet中添加一個(gè)可變對象后,并且后面程序修改了該可變對象的屬性,導(dǎo)致它與其他對象的大小順序發(fā)生改變,但TreeSet不會再次調(diào)整它們的順序,甚至可能導(dǎo)致TreeSet中保存這兩個(gè)對象,它們通過equals方法比較返回true,compareTo(Object obj)方法比較返回0.

如下程序所示:

 
 
 
  1. class R  
  2. {  
  3. int count;  
  4. public R(int count)  
  5. {  
  6. this.count = count;  
  7. }  
  8. public String toString()  
  9. {  
  10. return "R(count屬性:" + count + ")";  
  11. }  
  12. public boolean equals(Object obj)  
  13. {  
  14. if (obj instanceof R)  
  15. {  
  16. R r = (R)obj;  
  17. if (r.count == this.count)  
  18. {  
  19. return true;  
  20. }  
  21. }  
  22. return false;  
  23. }  
  24. public int hashCode()  
  25. {  
  26. return this.count;  
  27. }  
  28. }  
  29. public class TestHashSet2  
  30. {  
  31. public static void main(String[] args)  
  32. {  
  33. HashSet hs = new HashSet();  
  34. hs.add(new R(5));  
  35. hs.add(new R(-3));  
  36. hs.add(new R(9));  
  37. hs.add(new R(-2));  
  38. //打印TreeSet集合,集合元素是有序排列的  
  39. System.out.println(hs);  
  40. //取出第一個(gè)元素  
  41. Iterator it = hs.iterator();  
  42. R first = (R)it.next();  
  43. //為第一個(gè)元素的count屬性賦值  
  44. first.count = -3;  
  45. //再次輸出count將看到TreeSet里的元素處于無序狀態(tài)  
  46. System.out.println(hs);  
  47. hs.remove(new R(-3));  
  48. System.out.println(hs);  
  49. //輸出false  
  50. System.out.println("hs是否包含count為-3的R對象?" + hs.contains(new R(-3)));  
  51. //輸出false  
  52. System.out.println("hs是否包含count為5的R對象?" + hs.contains(new R(5)));  
  53.  
  54. }  
  55. }  
  56.  

程序運(yùn)行結(jié)果:

[R(count屬性:-3), R(count屬性:-2), R(count屬性:5), R(count屬性:9)]
[R(count屬性:20), R(count屬性:-2), R(count屬性:5), R(count屬性:-2)]
[R(count屬性:20), R(count屬性:-2), R(count屬性:5), R(count屬性:-2)]
[R(count屬性:20), R(count屬性:-2), R(count屬性:-2)]

說明:

上面程序中的R對象是一個(gè)正常重寫了equals方法和comparable方法類,這兩個(gè)方法都以R對象的count屬性作為判斷的依據(jù)??梢钥吹匠绦虻谝淮屋敵龅慕Y(jié)果是有序排列的。當(dāng)改變R對象的count屬性,程序的輸出結(jié)果也發(fā)生了改變,而且包含了重復(fù)元素。一旦改變了TreeSet集合里可變元素的屬性,當(dāng)再視圖刪除該對象時(shí),TreeSet也會刪除失敗(甚至集合中原有的、屬性沒被修改,但與修改后元素相等的元素也無法刪除),所以刪除count

為-2的R對象時(shí),沒有任何元素被刪除;程序可以刪除count為5的R對象,這表明TreeSet可以刪除沒有被修改屬性、且不與其他被修改屬性的對象重復(fù)的對象。

總結(jié):與HashSet在處理這些對象時(shí)將非常復(fù)雜,而且容易出錯。為了讓程序更具健壯,推薦HashSet和TreeSet集合中只放入不可變對象。

#p#

2、定制排序

TreeSet的自然排序是根據(jù)集合元素的大小,TreeSet將他們以升序排列。如果需要實(shí)現(xiàn)定制排序,例如降序,則可以使用Comparator接口。該接口里包含一個(gè)int compare(T o1, T o2)方法,該方法用于比較o1和o2的大小。

如果需要實(shí)現(xiàn)定制排序,則需要在創(chuàng)建TreeSet集合對象時(shí),并提供一個(gè)Comparator對象與該TreeSet集合關(guān)聯(lián),由該Comparator對象負(fù)責(zé)集合元素的排序邏輯。

如下程序所示:

 
 
 
  1. class M {  
  2. int age;  
  3.  
  4. public M(int age) {  
  5. this.age = age;  
  6. }  
  7.  
  8. public String toString() {  
  9. return "M對象(age:" + age + ")";  
  10. }  
  11. }  
  12.  
  13. public class TestTreeSet3 {  
  14. public static void main(String[] args) {  
  15. TreeSet ts = new TreeSet(new Comparator() {  
  16. public int compare(Object o1, Object o2) {  
  17.  
  18. M m1 = (M) o1;  
  19. M m2 = (M) o2;  
  20.  
  21. if (m1.age > m2.age) {  
  22. return -1;  
  23. } else if (m1.age == m2.age) {  
  24. return 0;  
  25. } else {  
  26. return 1;  
  27. }  
  28. }  
  29. });  
  30. ts.add(new M(5));  
  31. ts.add(new M(-3));  
  32. ts.add(new M(9));  
  33. System.out.println(ts);  
  34. }  
  35. }  
  36.  

程序運(yùn)行結(jié)果:

[M對象(age:9), M對象(age:5), M對象(age:-3)]

說明:

上面程序中創(chuàng)建了一個(gè)Comparator接口的匿名內(nèi)部類對象,該對象負(fù)責(zé)ts集合的排序。所以當(dāng)我們把M對象添加到ts集合中時(shí),無須M類實(shí)現(xiàn)Comparable接口,因?yàn)榇藭r(shí)TreeSet無須通過M對象來比較大小,而是由與TreeSet關(guān)聯(lián)的Comparator對象來負(fù)責(zé)集合元素的排序。使用定制排序時(shí),TreeSet對集合元素排序時(shí)不管集合元素本身的大小,而是由Comparator對象負(fù)責(zé)集合元素的排序規(guī)則。


新聞名稱:Java集合框架總結(jié):TreeSet類的排序問題
轉(zhuǎn)載來于:http://www.dlmjj.cn/article/dpgjoco.html