亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

解決TreeSet類的排序問題

2019-11-26 14:59:05
字體:
來源:轉載
供稿:網友

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

1、自然排序

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

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

java常用類實現Comparable接口,并提供了比較大小的標準。實現Comparable接口的常用類:

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

如果試圖把一個對象添加進TreeSet時,則該對象的類必須實現Comparable接口。

如下程序則會報錯:

class Err { } public class TestTreeSetError { public static void main(String[] args) { TreeSet ts = new TreeSet(); //向TreeSet集合中添加兩個Err對象 ts.add(new Err()); ts.add(new Err()); } } 

說明:

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

當采用compareTo(Object obj)方法比較對象時,都需要將被比較對象obj強制類型轉換成相同類型,因為只有相同類的兩個實例才能比較大小。即向TreeSet中添加的應該是同一個類的對象,否則會引發ClassCastException異常。例如,當向TreeSet中添加一個字符串對象,這個操作完全正常。當添加第二個Date對象時,TreeSet就好調用該對象的compareTo(Object obj)方法與集合中其他元素進行比較,則此時程序會引發異常。

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

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

對于TreeSet集合而言,它判斷兩個對象不相等的標準是:兩個對象通過equals方法比較返回false,或通過compareTo(Object obj)比較沒有返回0――即使兩個對象時同一個對象,TreeSet也會把它們當成兩個對象進行處理。

如下程序所示:

//Z類,重寫了equals方法,總是返回false, //重寫了compareTo(Object obj)方法,總是返回正整數 class Z implements Comparable { int age; public Z(int age) { this.age = age; } public boolean equals(Object obj) { return false; } public int compareTo(Object obj) { return 1; } } public class TestTreeSet { public static void main(String[] args) { TreeSet set = new TreeSet(); Z z1 = new Z(6); set.add(z1); System.out.println(set.add(z1)); //下面輸出set集合,將看到有2個元素 System.out.println(set); //修改set集合的第一個元素的age屬性 ((Z)(set.first())).age = 9; //輸出set集合的最后一個元素的age屬性,將看到也變成了9 System.out.println(((Z)(set.last())).age); } } 

 程序運行結果:

true
[TreeSet.Z@1fb8ee3,
TreeSet.Z@1fb8ee3]
9
說明:

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

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

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

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

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

如下程序所示:

class R { int count; public R(int count) { this.count = count; } public String toString() { return "R(count屬性:" + count + ")"; } public boolean equals(Object obj) { if (obj instanceof R) { R r = (R)obj; if (r.count == this.count) { return true; } } return false; } public int hashCode() { return this.count; } } public class TestHashSet2 { public static void main(String[] args) { HashSet hs = new HashSet(); hs.add(new R(5)); hs.add(new R(-3)); hs.add(new R(9)); hs.add(new R(-2)); //打印TreeSet集合,集合元素是有序排列的 System.out.println(hs); //取出第一個元素 Iterator it = hs.iterator(); R first = (R)it.next(); //為第一個元素的count屬性賦值 first.count = -3; //再次輸出count將看到TreeSet里的元素處于無序狀態 System.out.println(hs); hs.remove(new R(-3)); System.out.println(hs); //輸出false System.out.println("hs是否包含count為-3的R對象?" + hs.contains(new R(-3))); //輸出false System.out.println("hs是否包含count為5的R對象?" + hs.contains(new R(5)));  } }  

程序運行結果:

[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對象是一個正常重寫了equals方法和comparable方法類,這兩個方法都以R對象的count屬性作為判斷的依據??梢钥吹匠绦虻谝淮屋敵龅慕Y果是有序排列的。當改變R對象的count屬性,程序的輸出結果也發生了改變,而且包含了重復元素。一旦改變了TreeSet集合里可變元素的屬性,當再視圖刪除該對象時,TreeSet也會刪除失?。ㄉ踔良现性械?、屬性沒被修改,但與修改后元素相等的元素也無法刪除),所以刪除count

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

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

2、定制排序

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

如果需要實現定制排序,則需要在創建TreeSet集合對象時,并提供一個Comparator對象與該TreeSet集合關聯,由該Comparator對象負責集合元素的排序邏輯。

如下程序所示:

class M { int age;  public M(int age) { this.age = age; }  public String toString() { return "M對象(age:" + age + ")"; } }  public class TestTreeSet3 { public static void main(String[] args) { TreeSet ts = new TreeSet(new Comparator() { public int compare(Object o1, Object o2) {  M m1 = (M) o1; M m2 = (M) o2;  if (m1.age > m2.age) { return -1; } else if (m1.age == m2.age) { return 0; } else { return 1; } } }); ts.add(new M(5)); ts.add(new M(-3)); ts.add(new M(9)); System.out.println(ts); } }  

程序運行結果:

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

上面程序中創建了一個Comparator接口的匿名內部類對象,該對象負責ts集合的排序。所以當我們把M對象添加到ts集合中時,無須M類實現Comparable接口,因為此時TreeSet無須通過M對象來比較大小,而是由與TreeSet關聯的Comparator對象來負責集合元素的排序。使用定制排序時,TreeSet對集合元素排序時不管集合元素本身的大小,而是由Comparator對象負責集合元素的排序規則。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
成人黄色免费在线观看| 国产日韩欧美在线播放| 亚洲xxxx在线| 亚洲欧美日韩在线一区| 国产成人精品日本亚洲| 欧美日韩人人澡狠狠躁视频| 亚洲国产精品系列| 国产综合在线视频| 成人免费淫片aa视频免费| 国产主播在线一区| 亚洲自拍小视频免费观看| 日韩在线国产精品| 最近2019年好看中文字幕视频| 欧美裸体xxxx极品少妇软件| 法国裸体一区二区| 国产日韩精品电影| 国产一区二区三区高清在线观看| 久久久精品日本| 欧美国产亚洲视频| 亚洲一区二区三区在线视频| 国产成人一区三区| 日本精品在线视频| 欧美一级片久久久久久久| 亚洲色图17p| 97视频色精品| 久久久久久久国产| 欧美精品在线看| 国产午夜精品一区理论片飘花| 久久天天躁狠狠躁老女人| 午夜欧美不卡精品aaaaa| 日韩一区二区三区xxxx| 日韩有码在线观看| 海角国产乱辈乱精品视频| 亚洲精品国偷自产在线99热| 在线播放日韩精品| 欧美激情女人20p| 欧美xxxx综合视频| 国产精品久久久久999| 亚洲区bt下载| 欧美激情成人在线视频| 欧美成人免费全部观看天天性色| 欧美极品xxxx| 69视频在线免费观看| 亚洲精品在线视频| 欧美肥臀大乳一区二区免费视频| 欧美日韩国产成人高清视频| 中国日韩欧美久久久久久久久| 97久久精品人人澡人人爽缅北| 2020欧美日韩在线视频| 国内精品国产三级国产在线专| 日韩在线观看成人| 亚洲韩国欧洲国产日产av| 亚洲码在线观看| 日韩在线观看免费网站| 国外成人在线播放| 国产欧美婷婷中文| 成人免费午夜电影| 亚洲欧美日韩国产中文| 欧美大尺度在线观看| 久久免费成人精品视频| 在线观看国产精品淫| 国产精品高潮视频| 亚洲精品欧美日韩| 国产精品综合久久久| 91精品在线观看视频| 欧美精品免费在线| 久久男人资源视频| 成人国产精品av| 国内外成人免费激情在线视频网站| 国产精品高清免费在线观看| 国产美女91呻吟求| 国产69精品久久久久久| 精品调教chinesegay| 国产精品免费小视频| 久久精品99国产精品酒店日本| 亚洲电影天堂av| 亚洲激情视频在线观看| 海角国产乱辈乱精品视频| 第一福利永久视频精品| 韩国视频理论视频久久| 中文字幕精品影院| 精品中文字幕在线| 欧美日韩国产一区在线| 久久久久一本一区二区青青蜜月| 在线日韩第一页| 亚洲乱码国产乱码精品精| 亚洲人成绝费网站色www| 国产精品igao视频| 韩国精品美女www爽爽爽视频| 欧美洲成人男女午夜视频| 亚洲的天堂在线中文字幕| 精品国产91久久久久久老师| 欧美国产日韩在线| 欧美激情亚洲自拍| 午夜免费在线观看精品视频| 亚洲一区制服诱惑| 精品久久久久久久久国产字幕| 国产精品视频中文字幕91| 黑人欧美xxxx| 欧美日韩国产丝袜另类| 日韩欧美在线免费| 日韩一区二区福利| 久久久久久久久久婷婷| 国内精品久久久久久中文字幕| 国模吧一区二区三区| 亚洲成人网在线观看| 8050国产精品久久久久久| 中文字幕日韩电影| 综合网日日天干夜夜久久| 91精品国产高清久久久久久91| 亚洲国产精品成人精品| 亚洲a一级视频| 国产亚洲在线播放| 最近2019年手机中文字幕| 欧美天天综合色影久久精品| 国产精品三级美女白浆呻吟| 中文日韩在线观看| 一区二区三区国产视频| 91天堂在线视频| 青青在线视频一区二区三区| 中文字幕国产日韩| 亚洲网站在线观看| 久久久久久久久久久免费精品| 国内精品小视频在线观看| 久久九九免费视频| 在线播放日韩专区| 国产欧美在线观看| 国产在线视频欧美| 久久精品91久久久久久再现| 亚洲男人天堂古典| 色哟哟网站入口亚洲精品| 久久久久久久成人| 久久精品一偷一偷国产| 国产精品一区二区三区在线播放| 久久69精品久久久久久久电影好| 久久国产精品电影| 国产精品看片资源| 狠狠色狠狠色综合日日小说| 亚洲视频在线观看网站| 91在线观看免费高清完整版在线观看| 国产美女直播视频一区| 亚洲91精品在线| 美女久久久久久久久久久| 中文字幕av日韩| 国产免费一区二区三区香蕉精| 国产精品视频26uuu| 欧美专区在线视频| 91精品视频在线| 亚洲精品成人免费| 欧美成人黄色小视频| 日本三级韩国三级久久| 欧洲亚洲女同hd| 国语自产精品视频在免费| 国产精品久久久久久婷婷天堂| 日韩视频―中文字幕| 91美女片黄在线观看游戏| 亚洲免费av电影| 国产乱肥老妇国产一区二| 亚洲无限乱码一二三四麻| 欧美一区二三区| 精品中文字幕在线2019| 45www国产精品网站| 欧美性xxxxxxx| 国产精品精品久久久|