最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決TreeSet類(lèi)的排序問(wèn)題

 更新時(shí)間:2015年09月21日 16:50:47   投稿:lijiao  
本文介紹TreeSet支持兩種排序方法:自然排序和定制排序。TreeSet默認(rèn)采用自然排序。詳細(xì)請(qǐng)看下文

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

1、自然排序

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

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

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

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

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

如下程序則會(huì)報(bào)錯(cuò):

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

說(shuō)明:

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

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

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

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

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

如下程序所示:

//Z類(lèi),重寫(xiě)了equals方法,總是返回false, 
//重寫(xiě)了compareTo(Object obj)方法,總是返回正整數(shù) 
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個(gè)元素 
System.out.println(set); 
//修改set集合的第一個(gè)元素的age屬性 
((Z)(set.first())).age = 9; 
//輸出set集合的最后一個(gè)元素的age屬性,將看到也變成了9 
System.out.println(((Z)(set.last())).age); 
} 
} 

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

true
[TreeSet.Z@1fb8ee3,
TreeSet.Z@1fb8ee3]
9
說(shuō)明:

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

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

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

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

如果向TreeSet中添加一個(gè)可變對(duì)象后,并且后面程序修改了該可變對(duì)象的屬性,導(dǎo)致它與其他對(duì)象的大小順序發(fā)生改變,但TreeSet不會(huì)再次調(diào)整它們的順序,甚至可能導(dǎo)致TreeSet中保存這兩個(gè)對(duì)象,它們通過(guò)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); 
//取出第一個(gè)元素 
Iterator it = hs.iterator(); 
R first = (R)it.next(); 
//為第一個(gè)元素的count屬性賦值 
first.count = -3; 
//再次輸出count將看到TreeSet里的元素處于無(wú)序狀態(tài) 
System.out.println(hs); 
hs.remove(new R(-3)); 
System.out.println(hs); 
//輸出false 
System.out.println("hs是否包含count為-3的R對(duì)象?" + hs.contains(new R(-3))); 
//輸出false 
System.out.println("hs是否包含count為5的R對(duì)象?" + hs.contains(new R(5))); 
 
} 
} 
 

程序運(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)]

說(shuō)明:

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

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

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

2、定制排序

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

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

如下程序所示:

class M { 
int age; 
 
public M(int age) { 
this.age = age; 
} 
 
public String toString() { 
return "M對(duì)象(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); 
} 
} 
 

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

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

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

相關(guān)文章

  • java對(duì)象對(duì)比之comparable和comparator的區(qū)別

    java對(duì)象對(duì)比之comparable和comparator的區(qū)別

    今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著comparable和comparator的區(qū)別展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 創(chuàng)建一個(gè)Java的不可變對(duì)象

    創(chuàng)建一個(gè)Java的不可變對(duì)象

    這篇文章主要介紹了創(chuàng)建一個(gè)Java的不可變對(duì)象,一個(gè)類(lèi)的對(duì)象在通過(guò)構(gòu)造方法創(chuàng)建后如果狀態(tài)不會(huì)再被改變,那么它就是一個(gè)不可變(immutable)類(lèi)。它的所有成員變量的賦值僅在構(gòu)造方法中完成,不會(huì)提供任何 setter 方法供外部類(lèi)去修改,需要的朋友可以參考下
    2021-11-11
  • springboot項(xiàng)目啟動(dòng),但是訪問(wèn)報(bào)404錯(cuò)誤的問(wèn)題

    springboot項(xiàng)目啟動(dòng),但是訪問(wèn)報(bào)404錯(cuò)誤的問(wèn)題

    這篇文章主要介紹了springboot項(xiàng)目啟動(dòng),但是訪問(wèn)報(bào)404錯(cuò)誤的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • mybatis實(shí)現(xiàn)圖書(shū)管理系統(tǒng)

    mybatis實(shí)現(xiàn)圖書(shū)管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了mybatis實(shí)現(xiàn)圖書(shū)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • IDEA插件(BindED)之查看class文件的十六進(jìn)制

    IDEA插件(BindED)之查看class文件的十六進(jìn)制

    這篇文章主要介紹了IDEA插件(BindED)之查看class文件的十六進(jìn)制,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • spring?IOC控制反轉(zhuǎn)原理詳解

    spring?IOC控制反轉(zhuǎn)原理詳解

    這篇文章主要為大家詳細(xì)介紹了spring?IOC控制反轉(zhuǎn)原理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • spring boot配置ssl(多cer格式)超詳細(xì)教程

    spring boot配置ssl(多cer格式)超詳細(xì)教程

    這篇文章主要介紹了spring boot配置ssl(多cer格式)超詳細(xì)教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-11-11
  • 詳解java 拼音首字母搜索內(nèi)容功能的示例

    詳解java 拼音首字母搜索內(nèi)容功能的示例

    這篇文章主要介紹了詳解java 拼音首字母搜索內(nèi)容功能的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java通過(guò)Timer與TimerTask實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度方式

    Java通過(guò)Timer與TimerTask實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度方式

    本文介紹了如何在Java中使用`Timer`和`TimerTask`類(lèi)來(lái)實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度,`Timer`類(lèi)用于創(chuàng)建計(jì)時(shí)器并安排任務(wù),而`TimerTask`類(lèi)用于定義具體的任務(wù),文章詳細(xì)介紹了這兩個(gè)類(lèi)的方法和使用示例,包括創(chuàng)建任務(wù)、安排任務(wù)、取消任務(wù)等操作,通過(guò)一個(gè)簡(jiǎn)單的例子
    2024-12-12
  • Javaweb請(qǐng)求轉(zhuǎn)發(fā)及重定向?qū)崿F(xiàn)詳解

    Javaweb請(qǐng)求轉(zhuǎn)發(fā)及重定向?qū)崿F(xiàn)詳解

    這篇文章主要介紹了Javaweb請(qǐng)求轉(zhuǎn)發(fā)及重定向?qū)崿F(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07

最新評(píng)論

黔西县| 东明县| 鲜城| 沧州市| 双辽市| 玉溪市| 贵港市| 灵山县| 日喀则市| 丰原市| 九江县| 日土县| 舞钢市| 左权县| 卢氏县| 蒙城县| 溆浦县| 东台市| 额尔古纳市| 安仁县| 会理县| 日喀则市| 沐川县| 秦安县| 白玉县| 兰考县| 罗山县| 高邮市| 中宁县| 南投市| 梁平县| 永仁县| 遂平县| 棋牌| 大丰市| 从江县| 乌兰县| 枣强县| 扬中市| 尉氏县| 华安县|