轉載自:http://www.cnblogs.com/z2002m/archive/2011/10/24/2222780.html
ThreeSet能夠對集合中的對象排序,當TreeSet想集合中加入一個對象時,會把它插入到有序的對象序列中。那麼TreeSet是如何排序呢?TreeSet支持兩種排序方式:自然排序和客戶化排序.在默認情況下TreeSet採用自然排序方式。
先來介紹介紹什麼是自然排序吧
1、自然排序
在JDK類庫中,有一部分類實現了Comparable接口,如Integer Double和String等。
Comparable接口有一個comparTo(Object o)方法,它返回整數類型。對於表達式x.compareTo(y),如果返回值爲0,則表示x和y相等,如果返回值大於0,則表示x大於y,如果返回值小於0,則表示x小於y.TreeSet集合調用對象的compareTo()方法比較集合中的大小,注意鳥 不是TreeSet調用它自己的comparTo()方法而是它調用集合中對象的comparTo()方法.TreeSet類本身並沒有實現Comparable接口,然後進行升序排列,這種方式稱爲自然排序.
有人可能要問TreeSet集合怎麼給對象排序的按對象的什麼排序的?
下面簡單總結一哈
JDK類庫中實現了Comparable接口的一些類的排序方式
類 BigDecimal BigInteger Byte Double Float Integer Long Short 排序方式是 | 按數字大小排序 |
類 Character是 | 按字符的Unicode值的數字大小排序 |
類 String是 | 按字符中字符的Unicode值排序 |
這裏一定要灰常注意:使用自然排序時只能向集合中加入同類型的對象,並且這些對象的類必須實現Comparable接口
下面來說說Comparable接口和Comparator接口的區別
Comparator位於包java.util下,而Comparable位於包 java.lang下
Comparable 是一個對象本身就已經支持自比較所需要實現的接口(如 String、Integer 自己就可以完成比較大小操作,已經實現了Comparable接口) 此接口強行對實現它的每個類的對象進行整體排序。這種排序被稱爲類的自然排序,類的 compareTo 方法被稱爲它的自然比較方法。
比如你有一個Customer類 想讓這個類的實例加入集合後自動就具有某種排序功能只要這些實例加入集合後 就會按照你給Customer對象設定的方式排序
代碼:
- 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;
- // 先按照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;
- }
- @Override
- public 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());
- }
- }
- }
有人會問 重寫hashCode()方法 equals方法幹嘛 別急 慢慢道來
實際上,所有實現 Comparable 的 Java 核心類都具有與 equals 一致的自然排序。java.math.BigDecimal 是個例外,它的自然排序將值相等但精確度不同的 BigDecimal 對象(比如 4.0 和 4.00)視爲相等。爲了保證TreeSet能正確地排序,要求Customer類的compareTo()方法與equals()方法按相同的規則比較兩個Customer對象是否相等.也就是說,如果customer1.equals(customer2)爲True,那麼customer1.compareTo(customer2)爲0。 既然重寫了equals方法 就得重寫hashCode()方法這個大家都知道
大家看一眼結果便知 這個按照升序排序的 年齡也是按照升序
還有要注意哦,對於TreeSet中已經存在的Customer對象,如果修改了它們的name屬性或age屬性,則TreeSet不會對集合進行重新排序.例如下邊的代碼先把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);
- //customer1.setAge(20);//修改customer1實例的age
- Iterator<Customer> it=set.iterator();
- while(it.hasNext()){
- Customer customer=it.next();
- System.out.println(customer.getName()+" "+customer.getAge());
- }
- }
- }
上邊我先把 這句註釋掉
打印結果是:
這個是我們要的結果 name 和age都是按照升序排序的
然後我們把那句取消註釋之後的打印結果是:
Tom 20如果按照升序應該在下邊 但是卻在上邊 說明TreeSet沒有給它重新排序哦在實際應用中Customer對象的name屬性和age屬性肯定應該是可以被修改的,因此不適合用TreeSet來排序。那大家也應該能想到最適合用TreeSet排序的就是不可變類了唄 比如Integer,Double,String等 所謂不可變類,是指當創建了這個類的實例後,就不允許修改它的屬性值。大家以後用還是小心點好兒!
客戶化排序
Comparator這個單詞啥意思? 你知道不? 比較器的意思 學好英語還是挺好滴
除了自然排序,TreeSet還支持客戶化排序.java.util.Comparator<Type>接口提供具體的排序方式,<Type>指定被比較的對象的類型,Comparator有個compar(Type x,Type y)方法,用於比較兩個對象的大小,當compare(x,y)大於0時表示x大於y,小於0表示x小於y
等於0表示x等於y
來個例子如果希望TreeSet按照Customer對象的name屬性進行降序排列,可以先創建一個實現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());
- }
- }
- }
以上main方法在構造TreeSet的實例時,調用了它的TreeSet(Comparator comparator)構造方法.
這是幹甚? 其實就是指定一個比較器 TreeSet集合裏邊的對象按照這個比較器的規則進行排序 我把TreeSet類的這個構造方法搞上來看看就明白了 TreeSet裏邊有這樣一個構造方法
TreeSet
public TreeSet(Comparator<? super E> comparator)構造一個新的空 TreeSet,它根據指定比較器進行排序。插入到該 set 的所有元素都必須能夠由指定比較器進行相互比較:對於 set 中的任意兩個元素 e1 和 e2,執行 comparator.compare(e1, e2) 都不得拋出 ClassCastException。如果用戶試圖將違反此約束的元素添加到 set 中,則 add 調用將拋出 ClassCastException。
參數:
comparator - 將用來對此 set 進行排序的比較器。如果該參數爲 null,則使用元素的自然順序。
最後的打印結果是:
是倒序 ...
那你現在是不知道了comparable接口和comparable接口的區別了並且也能更好的使用TreeSet集合了
總結一下吧
單點解釋吧:用自定義類實現Comparable接口,那麼這個類就具有排序功能,Comparable和具體你要進行排序的類的實例邦定。而Comparator比較靈活,只需要通過構造方法指定一個比較器就行了實現它的自定義類僅僅定義了一種排序方式或排序規則。不言而喻,這種方式比較靈活。我們的要排序的類可以分別和多個實現Comparator接口的類綁定,從而達到可以按自己的意願實現按多種方式排序的目的。Comparable——“靜態綁定排序”,Comparator——“動態綁定排序”。
在多墨跡一點 說說編寫java類時應該養成一些好習慣吧
一: 如果java類重新定義了equals方法,那麼這個類也必須重新定義hashCode()方法,並且保證當兩個對象用equals方法比較結果爲true時,這兩個對象的hashCode()方法的返回值相等.
二:如果java類實現了Comparable接口,那麼這個類應該從新定義compareTo() equals() 和hashCode()方法,保證compareTo()和equals()方法採用相同的比較規則來比較兩個對象是否相等,並且保證當兩個對象用equals()方法比較的結果爲true時,這兩個對象的hashCode()方法的返回值相等.
HashSet和HashMap具有較好的性能,是Set和Map首選實現類,只有在需要排序的場合,才考慮使用TreeSet和TreeMap. LinkedList 和 ArrayList各有優缺點,如果經常對元素執行插入和刪除操作,那麼可以用LinkedList,如果經常隨機訪問元素,那麼可以用ArrayList.
ThreeSet能夠對集合中的對象排序,當TreeSet想集合中加入一個對象時,會把它插入到有序的對象序列中。那麼TreeSet是如何排序呢?TreeSet支持兩種排序方式:自然排序和客戶化排序.在默認情況下TreeSet採用自然排序方式。
先來介紹介紹什麼是自然排序吧
1、自然排序
在JDK類庫中,有一部分類實現了Comparable接口,如Integer Double和String等。
Comparable接口有一個comparTo(Object o)方法,它返回整數類型。對於表達式x.compareTo(y),如果返回值爲0,則表示x和y相等,如果返回值大於0,則表示x大於y,如果返回值小於0,則表示x小於y.TreeSet集合調用對象的compareTo()方法比較集合中的大小,注意鳥 不是TreeSet調用它自己的comparTo()方法而是它調用集合中對象的comparTo()方法.TreeSet類本身並沒有實現Comparable接口,然後進行升序排列,這種方式稱爲自然排序.
有人可能要問TreeSet集合怎麼給對象排序的按對象的什麼排序的?
下面簡單總結一哈
JDK類庫中實現了Comparable接口的一些類的排序方式
類 BigDecimal BigInteger Byte Double Float Integer Long Short 排序方式是 | 按數字大小排序 |
類 Character是 | 按字符的Unicode值的數字大小排序 |
類 String是 | 按字符中字符的Unicode值排序 |
這裏一定要灰常注意:使用自然排序時只能向集合中加入同類型的對象,並且這些對象的類必須實現Comparable接口
下面來說說Comparable接口和Comparator接口的區別
Comparator位於包java.util下,而Comparable位於包 java.lang下
Comparable 是一個對象本身就已經支持自比較所需要實現的接口(如 String、Integer 自己就可以完成比較大小操作,已經實現了Comparable接口) 此接口強行對實現它的每個類的對象進行整體排序。這種排序被稱爲類的自然排序,類的 compareTo 方法被稱爲它的自然比較方法。
比如你有一個Customer類 想讓這個類的實例加入集合後自動就具有某種排序功能只要這些實例加入集合後 就會按照你給Customer對象設定的方式排序
代碼:
- 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;
- // 先按照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;
- }
- @Override
- public 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());
- }
- }
- }
- //打印結果
- Mike 15
- Tom 15
- Tom 20
有人會問 重寫hashCode()方法 equals方法幹嘛 別急 慢慢道來
實際上,所有實現 Comparable 的 Java 核心類都具有與 equals 一致的自然排序。java.math.BigDecimal 是個例外,它的自然排序將值相等但精確度不同的 BigDecimal 對象(比如 4.0 和 4.00)視爲相等。爲了保證TreeSet能正確地排序,要求Customer類的compareTo()方法與equals()方法按相同的規則比較兩個Customer對象是否相等.也就是說,如果customer1.equals(customer2)爲True,那麼customer1.compareTo(customer2)爲0。 既然重寫了equals方法 就得重寫hashCode()方法這個大家都知道
大家看一眼結果便知 這個按照升序排序的 年齡也是按照升序
還有要注意哦,對於TreeSet中已經存在的Customer對象,如果修改了它們的name屬性或age屬性,則TreeSet不會對集合進行重新排序.例如下邊的代碼先把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);
- //customer1.setAge(20);//修改customer1實例的age
- Iterator<Customer> it=set.iterator();
- while(it.hasNext()){
- Customer customer=it.next();
- System.out.println(customer.getName()+" "+customer.getAge());
- }
- }
- }
上邊我先把
- customer1.setAge(20);
打印結果是:
- Tom 15
- Tom 16
然後我們把那句取消註釋之後的打印結果是:
- Tom 20
- Tom 16
Tom 20如果按照升序應該在下邊 但是卻在上邊 說明TreeSet沒有給它重新排序哦在實際應用中Customer對象的name屬性和age屬性肯定應該是可以被修改的,因此不適合用TreeSet來排序。那大家也應該能想到最適合用TreeSet排序的就是不可變類了唄 比如Integer,Double,String等 所謂不可變類,是指當創建了這個類的實例後,就不允許修改它的屬性值。大家以後用還是小心點好兒!
客戶化排序
Comparator這個單詞啥意思? 你知道不? 比較器的意思 學好英語還是挺好滴
除了自然排序,TreeSet還支持客戶化排序.java.util.Comparator<Type>接口提供具體的排序方式,<Type>指定被比較的對象的類型,Comparator有個compar(Type x,Type y)方法,用於比較兩個對象的大小,當compare(x,y)大於0時表示x大於y,小於0表示x小於y
等於0表示x等於y
來個例子如果希望TreeSet按照Customer對象的name屬性進行降序排列,可以先創建一個實現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());
- }
- }
- }
以上main方法在構造TreeSet的實例時,調用了它的TreeSet(Comparator comparator)構造方法.
- Set<Customer> set = new TreeSet<Customer>(new CustomerComparator());
TreeSet
public TreeSet(Comparator<? super E> comparator)構造一個新的空 TreeSet,它根據指定比較器進行排序。插入到該 set 的所有元素都必須能夠由指定比較器進行相互比較:對於 set 中的任意兩個元素 e1 和 e2,執行 comparator.compare(e1, e2) 都不得拋出 ClassCastException。如果用戶試圖將違反此約束的元素添加到 set 中,則 add 調用將拋出 ClassCastException。
參數:
comparator - 將用來對此 set 進行排序的比較器。如果該參數爲 null,則使用元素的自然順序。
最後的打印結果是:
- Tom 15
- Mike 26
- Jack 16
那你現在是不知道了comparable接口和comparable接口的區別了並且也能更好的使用TreeSet集合了
總結一下吧
單點解釋吧:用自定義類實現Comparable接口,那麼這個類就具有排序功能,Comparable和具體你要進行排序的類的實例邦定。而Comparator比較靈活,只需要通過構造方法指定一個比較器就行了實現它的自定義類僅僅定義了一種排序方式或排序規則。不言而喻,這種方式比較靈活。我們的要排序的類可以分別和多個實現Comparator接口的類綁定,從而達到可以按自己的意願實現按多種方式排序的目的。Comparable——“靜態綁定排序”,Comparator——“動態綁定排序”。
在多墨跡一點 說說編寫java類時應該養成一些好習慣吧
一: 如果java類重新定義了equals方法,那麼這個類也必須重新定義hashCode()方法,並且保證當兩個對象用equals方法比較結果爲true時,這兩個對象的hashCode()方法的返回值相等.
二:如果java類實現了Comparable接口,那麼這個類應該從新定義compareTo() equals() 和hashCode()方法,保證compareTo()和equals()方法採用相同的比較規則來比較兩個對象是否相等,並且保證當兩個對象用equals()方法比較的結果爲true時,這兩個對象的hashCode()方法的返回值相等.
HashSet和HashMap具有較好的性能,是Set和Map首選實現類,只有在需要排序的場合,才考慮使用TreeSet和TreeMap. LinkedList 和 ArrayList各有優缺點,如果經常對元素執行插入和刪除操作,那麼可以用LinkedList,如果經常隨機訪問元素,那麼可以用ArrayList.