ThreeSet能夠?qū)现械膶ο笈判?當(dāng)TreeSet想集合中加入一個對象時,會把它插入到有序的對象序列中。那么TreeSet是如何排序呢?TreeSet支持兩種排序方式:自然排序和客戶化排序.在默認(rèn)情況下TreeSet采用自然排序方式。
先來介紹介紹什么是自然排序吧
1、自然排序
在JDK類庫中,有一部分類實現(xiàn)了Comparable接口,如Integer Double和String等。
Comparable接口有一個comparTo(Objecto)方法,它返回整數(shù)類型。對于表達(dá)式x.compareTo(y),如果返回值為0,則表示x和y相等,如果返回值大于0,則表示x大于y,如果返回值小于0,則表示x小于y.TreeSet集合調(diào)用對象的compareTo()方法比較集合中的大小,注意鳥不是TreeSet調(diào)用它自己的comparTo()方法而是它調(diào)用集合中對象的comparTo()方法.TreeSet類本身并沒有實現(xiàn)Comparable接口,然后進(jìn)行升序排列,這種方式稱為自然排序.
有人可能要問TreeSet集合怎么給對象排序的按對象的什么排序的?
下面簡單總結(jié)一哈
JDK類庫中實現(xiàn)了Comparable接口的一些類的排序方式
類 BigDecimal BigInteger Byte Double Float Integer Long Short 排序方式是 | 按數(shù)字大小排序 |
類 Character是 | 按字符的Unicode值的數(shù)字大小排序 |
類 String是 | 按字符中字符的Unicode值排序 |
這里一定要灰常注意:使用自然排序時只能向集合中加入同類型的對象,并且這些對象的類必須實現(xiàn)Comparable接口
下面來說說Comparable接口和Comparator接口的區(qū)別
Comparator位于包java.util下,而Comparable位于包 java.lang下
Comparable 是一個對象本身就已經(jīng)支持自比較所需要實現(xiàn)的接口(如 String、Integer自己就可以完成比較大小操作,已經(jīng)實現(xiàn)了Comparable接口) 此接口強(qiáng)行對實現(xiàn)它的每個類的對象進(jìn)行整體排序。這種排序被稱為類的自然排序,類的 compareTo 方法被稱為它的自然比較方法。
比如你有一個Customer類 想讓這個類的實例加入集合后自動就具有某種排序功能只要這些實例加入集合后 就會按照你給Customer對象設(shè)定的方式排序
代碼:
- package hang.jihe;
-
- import java.util.HashSet;
- import java.util.Set;
-
- public class Customer implements Comparable {
- private String name;
-
- private int age;
-
- public Customer(String name, int age) {
- this.age = age;
- this.name = name;
- }
-
- public int getAge() {
- return age;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (!(obj instanceof Customer))
- return false;
- final Customer other = (Customer) obj;
-
- if (this.name.equals(other.getName()) && this.age == other.getAge())
- return true;
- else
- return false;
- }
-
- public static void main(String[] args) {
- Set<Customer> set = new HashSet<Customer>();
- Customer customer1 = new Customer("Tom", 15);
- Customer customer2 = new Customer("Tom", 15);
- set.add(customer1);
- set.add(customer2);
- System.out.println(set.size());
- }
-
- public int compareTo(Object o) {
- Customer other = (Customer) o;
-
-
- if (this.name.compareTo(other.getName()) > 0)
- return 1;
- if (this.name.compareTo(other.getName()) < 0)
- return -1;
-
-
- if (this.age > other.getAge())
- return 1;
- if (this.age < other.getAge())
- return -1;
- return 0;
- }
-
- @Override
- public int hashCode() {
- int result;
- result = (name == null ? 0 : name.hashCode());
- result = 29 * result + age;
- return result;
- }
- }
package hang.jihe;import java.util.HashSet;import java.util.Set;public class Customer implements Comparable {private String name;private int age;public Customer(String name, int age) {this.age = age;this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (!(obj instanceof Customer))return false;final Customer other = (Customer) obj;if (this.name.equals(other.getName()) && this.age == other.getAge())return true;elsereturn false;}public static void main(String[] args) {Set<Customer> set = new HashSet<Customer>();Customer customer1 = new Customer("Tom", 15);Customer customer2 = new Customer("Tom", 15);set.add(customer1);set.add(customer2);System.out.println(set.size());}public int compareTo(Object o) {Customer other = (Customer) o;// 先按照name屬性排序if (this.name.compareTo(other.getName()) > 0)return 1;if (this.name.compareTo(other.getName()) < 0)return -1;// 在按照age屬性排序if (this.age > other.getAge())return 1;if (this.age < other.getAge())return -1;return 0;}@Overridepublic int hashCode() {int result;result = (name == null ? 0 : name.hashCode());result = 29 * result + age;return result;}}
main方法的類
- package hang.jihe;
-
- import java.util.Iterator;
- import java.util.Set;
- import java.util.TreeSet;
-
- public class CustomerTester {
- public static void main(String[] args) {
- Set<Customer> set = new TreeSet<Customer>();
- set.add(new Customer("Tom",15));
- set.add(new Customer("Tom",20));
- set.add(new Customer("Tom",15));
- set.add(new Customer("Mike",15));
-
- Iterator<Customer> it = set.iterator();
- while(it.hasNext()){
- Customer customer = it.next();
- System.out.println(customer.getName()+" "+customer.getAge());
- }
- }
- }
package hang.jihe;import java.util.Iterator;import java.util.Set;import java.util.TreeSet;public class CustomerTester {public static void main(String[] args) {Set<Customer> set = new TreeSet<Customer>();set.add(new Customer("Tom",15));set.add(new Customer("Tom",20));set.add(new Customer("Tom",15));set.add(new Customer("Mike",15));Iterator<Customer> it = set.iterator();while(it.hasNext()){Customer customer = it.next();System.out.println(customer.getName()+" "+customer.getAge());}}}
//打印結(jié)果Mike 15Tom 15Tom 20
有人會問 重寫hashCode()方法 equals方法干嘛 別急
慢慢道來
實際上,所有實現(xiàn) Comparable 的 Java 核心類都具有與 equals一致的自然排序。java.math.BigDecimal 是個例外,它的自然排序?qū)⒅迪嗟鹊_度不同的 BigDecimal 對象(比如 4.0和4.00)視為相等。為了保證TreeSet能正確地排序,要求Customer類的compareTo()方法與equals()方法按相同的規(guī)則比較兩個Customer對象是否相等.也就是說,如果customer1.equals(customer2)為True,那么customer1.compareTo(customer2)為0。 既然重寫了equals方法 就得重寫hashCode()方法這個大家都知道
大家看一眼結(jié)果便知 這個按照升序排序的 年齡也是按照升序
還有要注意哦,對于TreeSet中已經(jīng)存在的Customer對象,如果修改了它們的name屬性或age屬性,則TreeSet不會對集合進(jìn)行重新排序.例如下邊的代碼先把customer1和customer2 對象加入到TreeSet集合中,然后修改customer1的age屬性
代碼:
- package hang.jihe;
-
- import java.util.Iterator;
- import java.util.Set;
- import java.util.TreeSet;
-
- public class TreeSetTest {
- public static void main(String[] args) {
- Set<Customer> set = new TreeSet<Customer>();
- Customer customer1 = new Customer("Tom",15);
- Customer customer2 = new Customer("Tom",16);
- set.add(customer1);
- set.add(customer2);
-
-
- Iterator<Customer> it=set.iterator();
- while(it.hasNext()){
- Customer customer=it.next();
- System.out.println(customer.getName()+" "+customer.getAge());
- }
- }
- }
package hang.jihe;import java.util.Iterator;import java.util.Set;import java.util.TreeSet;public class TreeSetTest {public static void main(String[] args) {Set<Customer> set = new TreeSet<Customer>();Customer customer1 = new Customer("Tom",15);Customer customer2 = new Customer("Tom",16);set.add(customer1);set.add(customer2);//customer1.setAge(20);//修改customer1實例的ageIterator<Customer> it=set.iterator();while(it.hasNext()){Customer customer=it.next();System.out.println(customer.getName()+" "+customer.getAge());}}}
上邊我先把
customer1.setAge(20);
這句注釋掉
打印結(jié)果是:
Tom 15Tom 16
這個是我們要的結(jié)果 name 和age都是按照升序排序的
然后我們把那句取消注釋之后的打印結(jié)果是:
Tom 20Tom 16
Tom 20如果按照升序應(yīng)該在下邊 但是卻在上邊說明TreeSet沒有給它重新排序哦在實際應(yīng)用中Customer對象的name屬性和age屬性肯定應(yīng)該是可以被修改的,因此不適合用TreeSet來排序。那大家也應(yīng)該能想到最適合用TreeSet排序的就是不可變類了唄 比如Integer,Double,String等所謂不可變類,是指當(dāng)創(chuàng)建了這個類的實例后,就不允許修改它的屬性值。大家以后用還是小心點好兒!
客戶化排序
Comparator這個單詞啥意思? 你知道不? 比較器的意思 學(xué)好英語還是挺好滴
除了自然排序,TreeSet還支持客戶化排序.java.util.Comparator<Type>接口提供具體的排序方式,<Type>指定被比較的對象的類型,Comparator有個compar(Type x,Typey)方法,用于比較兩個對象的大小,當(dāng)compare(x,y)大于0時表示x大于y,小于0表示x小于y
等于0表示x等于y
來個例子如果希望TreeSet按照Customer對象的name屬性進(jìn)行降序排列,可以先創(chuàng)建一個實現(xiàn)Comparator接口的類
代碼:
- package hang.jihe;
-
- import java.util.Comparator;
- import java.util.Iterator;
- import java.util.Set;
- import java.util.TreeSet;
-
- public class CustomerComparator implements Comparator<Customer>{
-
- public int compare(Customer c1, Customer c2) {
- if(c1.getName().compareTo(c2.getName())>0)return -1;
- if(c1.getName().compareTo(c2.getName())<0)return 1;
-
- return 0;
- }
-
- public static void main(String args[]){
- Set<Customer> set = new TreeSet<Customer>(new CustomerComparator());
-
- Customer customer1= new Customer("Tom",15);
- Customer customer3= new Customer("Jack",16);
- Customer customer2= new Customer("Mike",26);
- set.add(customer1);
- set.add(customer2);
- set.add(customer3);
-
- Iterator<Customer> it = set.iterator();
- while(it.hasNext()){
- Customer customer = it.next();
- System.out.println(customer.getName()+" "+customer.getAge());
- }
- }
-
- }
package hang.jihe;import java.util.Comparator;import java.util.Iterator;import java.util.Set;import java.util.TreeSet;public class CustomerComparator implements Comparator<Customer>{public int compare(Customer c1, Customer c2) {if(c1.getName().compareTo(c2.getName())>0)return -1;if(c1.getName().compareTo(c2.getName())<0)return 1;return 0;}public static void main(String args[]){Set<Customer> set = new TreeSet<Customer>(new CustomerComparator());Customer customer1= new Customer("Tom",15);Customer customer3= new Customer("Jack",16);Customer customer2= new Customer("Mike",26);set.add(customer1);set.add(customer2);set.add(customer3);Iterator<Customer> it = set.iterator();while(it.hasNext()){Customer customer = it.next();System.out.println(customer.getName()+" "+customer.getAge());}}}
以上main方法在構(gòu)造TreeSet的實例時,調(diào)用了它的TreeSet(Comparator comparator)構(gòu)造方法.
- Set<Customer> set = new TreeSet<Customer>(new CustomerComparator());
Set<Customer> set = new TreeSet<Customer>(new CustomerComparator());
這是干甚? 其實就是指定一個比較器 TreeSet集合里邊的對象按照這個比較器的規(guī)則進(jìn)行排序 我把TreeSet類的這個構(gòu)造方法搞上來看看就明白了 TreeSet里邊有這樣一個構(gòu)造方法
TreeSet
public TreeSet(Comparator<? superE> comparator)構(gòu)造一個新的空 TreeSet,它根據(jù)指定比較器進(jìn)行排序。插入到該 set的所有元素都必須能夠由指定比較器進(jìn)行相互比較:對于 set 中的任意兩個元素 e1 和 e2,執(zhí)行 comparator.compare(e1,e2) 都不得拋出 ClassCastException。如果用戶試圖將違反此約束的元素添加到 set 中,則 add 調(diào)用將拋出ClassCastException。
參數(shù):
comparator - 將用來對此 set 進(jìn)行排序的比較器。如果該參數(shù)為 null,則使用元素的自然順序。 最后的打印結(jié)果是:
Tom 15Mike 26Jack 16
是倒序 ...
那你現(xiàn)在是不知道了comparable接口和comparable接口的區(qū)別了并且也能更好的使用TreeSet集合了
總結(jié)一下吧
單點解釋吧:用自定義類實現(xiàn)Comparable接口,那么這個類就具有排序功能,Comparable和具體你要進(jìn)行排序的類的實例邦定。而Comparator比較靈活,只需要通過構(gòu)造方法指定一個比較器就行了實現(xiàn)它的自定義類僅僅定義了一種排序方式或排序規(guī)則。不言而喻,這種方式比較靈活。我們的要排序的類可以分別和多個實現(xiàn)Comparator接口的類綁定,從而達(dá)到可以按自己的意愿實現(xiàn)按多種方式排序的目的。Comparable——“靜態(tài)綁定排序”,Comparator——“動態(tài)綁定排序”。
在多墨跡一點 說說編寫java類時應(yīng)該養(yǎng)成一些好習(xí)慣吧
一: 如果java類重新定義了equals方法,那么這個類也必須重新定義hashCode()方法,并且保證當(dāng)兩個對象用equals方法比較結(jié)果為true時,這兩個對象的hashCode()方法的返回值相等.
二:如果java類實現(xiàn)了Comparable接口,那么這個類應(yīng)該從新定義compareTo() equals()和hashCode()方法,保證compareTo()和equals()方法采用相同的比較規(guī)則來比較兩個對象是否相等,并且保證當(dāng)兩個對象用equals()方法比較的結(jié)果為true時,這兩個對象的hashCode()方法的返回值相等.
HashSet和HashMap具有較好的性能,是Set和Map首選實現(xiàn)類,只有在需要排序的場合,才考慮使用TreeSet和TreeMap.LinkedList 和ArrayList各有優(yōu)缺點,如果經(jīng)常對元素執(zhí)行插入和刪除操作,那么可以用LinkedList,如果經(jīng)常隨機(jī)訪問元素,那么可以用ArrayList.