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

Java中自然排序和比較器排序詳解

 更新時間:2016年09月20日 10:16:59   投稿:daisy  
這篇文章給大家介紹Java中的排序并不是指插入排序、希爾排序、歸并排序等具體的排序算法。而是自然排序和比較器排序,文中通過實例代碼介紹的很詳細(xì),有需要的朋友們可以參考借鑒。

前言

當(dāng)指執(zhí)行插入排序、希爾排序、歸并排序等算法時,比較兩個對象“大小”的比較操作。我們很容易理解整型的 i>j 這樣的比較方式,但當(dāng)我們對多個對象進行排序時,如何比較兩個對象的“大小”呢?這樣的比較 stu1 > stu2 顯然是不可能通過編譯的。為了解決如何比較兩個對象大小的問題,JDK提供了兩個接口 java.lang.Comparable java.util.Comparator 。

一、自然排序:java.lang.Comparable

Comparable 接口中只提供了一個方法: compareTo(Object obj) ,該方法的返回值是 int 。如果返回值為正數(shù),則表示當(dāng)前對象(調(diào)用該方法的對象)比 obj 對象“大”;反之“小”;如果為零的話,則表示兩對象相等。

下面是一個實現(xiàn)了 Comparable 接口的 Student 類:

public class Student implements Comparable { 
 
 private int id; 
  
 private String name; 
 
 public Student() { 
  super(); 
 } 
 
 @Override 
 public int compareTo(Object obj) { 
  if (obj instanceof Student) { 
   Student stu = (Student) obj; 
   return id - stu.id; 
  } 
  return 0; 
 } 
 
 @Override 
 public String toString() { 
  return "<" + id + ", " + name + ">"; 
 } 
} 

Student 實現(xiàn)了自然排序接口 Comparable ,那么我們是怎么利用這個接口對一組 Student 對象進行排序的呢?我們在學(xué)習(xí)數(shù)組的時候,使用了一個類來給整型數(shù)組排序: java.util.Arrays 。我們使用 Arrays 的 sort 方法來給整型數(shù)組排序。翻翻 API 文檔就會發(fā)現(xiàn), Arrays 里給出了 sort 方法很多重載形式,其中就包括 sort(Object[] obj) ,也就是說 Arryas 也能對對象數(shù)組進行排序,排序過程中比較兩個對象“大小”時使用的就是 Comparable 接口的 compareTo 方法。

public class CompareTest { 
 
 public static void main(String[] args) { 
  Student stu1 = new Student(1, "Little"); 
  Student stu2 = new Student(2, "Cyntin"); 
  Student stu3 = new Student(3, "Tony"); 
  Student stu4 = new Student(4, "Gemini"); 
   
  Student[] stus = new Student[4]; 
  stus[0] = stu1; 
  stus[1] = stu4; 
  stus[2] = stu3; 
  stus[3] = stu2; 
  System.out.println(“Array: ” + Arrays.toString(stus)); 
  Arrays.sort(stus); 
  System.out.println(“Sort: ” + Arrays.toString(stus)); 
 } 
} 

Student 數(shù)組里添加元素的順序并不是按學(xué)號 id 來添加的。調(diào)用了 Arrays.sort(stus) 之后,對 Student 數(shù)組進行排序,不管 sort 是使用哪種排序算法來實現(xiàn)的,比較兩個對象“大小”這個操作,它是肯定要做的。那么如何比較兩個對象的“大小”? Student 實現(xiàn)的 Comparable 接口就發(fā)揮作用了。 sort 方法會將待比較的那個對象強制類型轉(zhuǎn)換成 Comparable ,并調(diào)用 compareTo 方法,根據(jù)其返回值來判斷這兩個對象的“大小”。所以,在這個例子中排序后的原 Student 亂序數(shù)組就變成了按學(xué)號排序的 Student 數(shù)組。

但是我們注意到,排序算法和 Student 類綁定了, Student 只有一種排序算法。但現(xiàn)實社會不是這樣的,如果我們不想按學(xué)號排序怎么辦?假如,我們想按姓名來給學(xué)生排序怎么辦?我們只能修改 Student 類的 Comparable 接口的 compareTo 方法,改成按姓名排序。如果在同一個系統(tǒng)里有兩個操作,一個是按學(xué)號排序,另外一個是按姓名排序,這怎么辦?不可能在 Student 類體中寫兩個 compareTo 方法的實現(xiàn)。這么看來Comparable就有局限性了。為了彌補這個不足,JDK 還為我們提供了另外一個排序方式,也就是下面要說的比較器排序。

二、比較器排序:java.util.Comparator

上面我提到了,之所以提供比較器排序接口,是因為有時需要對同一對象進行多種不同方式的排序,這點自然排序 Comparable 不能實現(xiàn)。另外, Comparator 接口的一個好處是將比較排序算法和具體的實體類分離了。

翻翻 API 會發(fā)現(xiàn), Arrays.sort 還有種重載形式:sort(T[] a, Comparator<? super T> c) ,這個方法參數(shù)的寫法用到了泛型,我們還沒講到。我們可以把它理解成這樣的形式: sort(Object[] a, Comparator c) ,這個方法的意思是按照比較器 c 給出的比較排序算法,對 Object 數(shù)組進行排序。Comparator 接口中定義了兩個方法: compare(Object o1, Object o2) equals 方法,由于 equals 方法所有對象都有的方法,因此當(dāng)我們實現(xiàn) Comparator 接口時,我們只需重寫 compare 方法,而不需重寫 equals 方法。Comparator 接口中對重寫 equals 方法的描述是:“注意,不重寫 Object.equals(Object) 方法總是安全的。然而,在某些情況下,重寫此方法可以允許程序確定兩個不同的 Comparator 是否強行實施了相同的排序,從而提高性能?!?。我們只需知道第一句話就OK了,也就是說,可以不用去想應(yīng)該怎么實現(xiàn) equals 方法,因為即使我們不顯示實現(xiàn) equals 方法,而是使用Object類的 equals 方法,代碼依然是安全的。

那么我們來寫個代碼,來用一用比較器排序。還是用 Student 類來做,只是沒有實現(xiàn) Comparable 接口。由于比較器的實現(xiàn)類只用顯示實現(xiàn)一個方法,因此,我們可以不用專門寫一個類來實現(xiàn)它,當(dāng)我們需要用到比較器時,可以寫個匿名內(nèi)部類來實現(xiàn) Comparator 。

下面是我們的按姓名排序的方法:

public void sortByName () { 
 Student stu1 = new Student(1, "Little"); 
 Student stu2 = new Student(2, "Cyntin"); 
 Student stu3 = new Student(3, "Tony"); 
 Student stu4 = new Student(4, "Gemini"); 
  
 Student[] stus = new Student[4]; 
 stus[0] = stu1; 
 stus[1] = stu4; 
 stus[2] = stu3; 
 stus[3] = stu2; 
 System.out.println("Array: " + Arrays.toString(stus)); 
 
 Arrays.sort(stus, new Comparator() { 
 
  @Override 
  public int compare(Object o1, Object o2) { 
   if (o1 instanceof Student && o2 instanceof Student) { 
    Student s1 = (Student) o1; 
    Student s2 = (Student) o2; 
    //return s1.getId() - s2.getId(); // 按Id排 
    return s1.getName().compareTo(s2.getName()); // 按姓名排 
   } 
   return 0; 
  } 
   
 }); 
  
 System.out.println("Sorted: " + Arrays.toString(stus)); 
} 

當(dāng)我們需要對Student按學(xué)號排序時,只需修改我們的排序方法中實現(xiàn)Comparator的內(nèi)部類中的代碼,而不用修改 Student 類。

注意: 當(dāng)然,你也可以用 Student 類實現(xiàn) Comparator 接口,這樣Student就是(is a)比較器了(Comparator)。當(dāng)需要使用這種排序的時候,將 Student 看作 Comparator 來使用就可以了,可以將 Student 作為參數(shù)傳入 sort 方法,因為 Student is a Comparator 。但這樣的代碼不是個優(yōu)秀的代碼,因為我們之所以使用比較器(Comparator),其中有個重要的原因就是,這樣可以把比較算法和具體類分離,降低類之間的耦合。

TreeSet對這兩種比較方式都提供了支持,分別對應(yīng)著TreeSet的兩個構(gòu)造方法:

     1、TreeSet():根據(jù)TreeSet中元素實現(xiàn)的 Comparable 接口的 compareTo 方法比較排序

   2、TreeSet(Comparator comparator):根據(jù)給定的 comparator 比較器,對 TreeSet 中的元素比較排序

當(dāng)向 TreeSet 中添加元素時,TreeSet 就會對元素進行排序。至于是用自然排序還是用比較器排序,就看你的 TreeSet 構(gòu)造是怎么寫的了。當(dāng)然,添加第一個元素時不會進行任何比較, TreeSet 中都沒有元素,和誰比去???

下面,分別給出使用兩種排序比較方式的 TreeSet 測試代碼:

/** 
 * 使用自然排序 
 * Student必須實現(xiàn)Comparable接口,否則會拋出ClassCastException 
 */ 
public void testSortedSet3() { 
 Student stu1 = new Student(1, "Little"); 
 Student stu2 = new Student(2, "Cyntin"); 
 Student stu3 = new Student(3, "Tony"); 
 Student stu4 = new Student(4, "Gemini"); 
 
 SortedSet set = new TreeSet(); 
 set.add(stu1); 
 set.add(stu3); // 若Student沒有實現(xiàn)Comparable接口,拋出ClassCastException 
 set.add(stu4); 
 set.add(stu2); 
 set.add(stu4); 
 set.add(new Student(12, "Little")); 
 
 System.out.println(set); 
} 
/** 
 * 使用比較器排序 
 * Student可以只是個簡單的Java類,不用實現(xiàn)Comparable接口 
 */ 
public void testSortedSet3() { 
 Student stu1 = new Student(1, "Little"); 
 Student stu2 = new Student(2, "Cyntin"); 
 Student stu3 = new Student(3, "Tony"); 
 Student stu4 = new Student(4, "Gemini"); 
 
 SortedSet set = new TreeSet(new Comparator() { 
 
  @Override 
  public int compare(Object o1, Object o2) { 
   if (o1 instanceof Student 
     && o2 instanceof Student) { 
    Student s1 = (Student) o1; 
    Student s2 = (Student) o2; 
    return s1.getName().compareTo(s2.getName()); 
   } 
   return 0; 
  } 
   
 }); 
 
 set.add(stu1); 
 set.add(stu3); 
 set.add(stu4); 
 set.add(stu2); 
 set.add(stu4); 
 set.add(new Student(12, "Little")); 
 
 System.out.println(set); 
} 

另外,介紹個工具類,java.util.Collections。注意,這不是Collection接口。Collections很像Arrays類。Arrays提供了一系列用于對數(shù)組操作的靜態(tài)方法,查找排序等等。Collections也提供了一系列這樣的方法,只是它是用于處理集合的,雖然Collections類和Collection接口很像,但是不要被Collections的名字給欺騙了,它不是只能處理Collection接口以及子接口的實現(xiàn)類,同樣也可以處理Map接口的實現(xiàn)類。

總結(jié)

Java中自然排序和比較器排序的介紹就到這里了,文章介紹的還是相對詳細(xì)的,希望能對大家的學(xué)習(xí)或者工作帶來一定的幫助,如果有疑問大家可以留言交流。

相關(guān)文章

  • Springboot @Configuration @bean注解作用解析

    Springboot @Configuration @bean注解作用解析

    這篇文章主要介紹了springboot @Configuration @bean注解作用解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • Java FutureTask類使用案例解析

    Java FutureTask類使用案例解析

    這篇文章主要介紹了Java FutureTask類使用案例解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值析,需要的朋友可以參考下
    2020-04-04
  • SpringBoot設(shè)置Session失效時間的解決方案

    SpringBoot設(shè)置Session失效時間的解決方案

    當(dāng)過期時間是大于1分鐘的時候是沒有什么問題的,但是如果設(shè)置過期時間小于1分鐘,就會失效,這篇文章主要介紹了SpringBoot設(shè)置Session失效時間的解決方案,需要的朋友可以參考下
    2024-05-05
  • Java使用itextpdf實現(xiàn)PDF轉(zhuǎn)文本以及轉(zhuǎn)圖片

    Java使用itextpdf實現(xiàn)PDF轉(zhuǎn)文本以及轉(zhuǎn)圖片

    PDF轉(zhuǎn)文本的插件常用的有pdfbox ,itextpdf 和 spire.pdf,本文主要介紹如何使用itextpdf實現(xiàn)PDF轉(zhuǎn)文本以及轉(zhuǎn)圖片,需要的可以參考一下
    2025-01-01
  • 詳解如何開發(fā)一個MyBatis通用Mapper的輪子

    詳解如何開發(fā)一個MyBatis通用Mapper的輪子

    因為一些原因,例如:通用數(shù)據(jù)權(quán)限控制、MyBatis-Plus好像不支持聯(lián)合主鍵等,我們不得不開發(fā)一個MyBatis通用Mapper的輪子。文中的示例代碼講解詳細(xì),需要的可以參考一下
    2022-12-12
  • springboot 實現(xiàn)記錄業(yè)務(wù)日志和異常業(yè)務(wù)日志的操作

    springboot 實現(xiàn)記錄業(yè)務(wù)日志和異常業(yè)務(wù)日志的操作

    這篇文章主要介紹了springboot 實現(xiàn)記錄業(yè)務(wù)日志和異常業(yè)務(wù)日志的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Spring Data JPA 整合QueryDSL的使用案例

    Spring Data JPA 整合QueryDSL的使用案例

    QueryDSL 是一個用于構(gòu)建類型安全的 SQL 查詢的 Java 庫,它的主要目標(biāo)是簡化在 Java 中構(gòu)建和執(zhí)行 SQL 查詢的過程,同時提供類型安全性和更好的編碼體驗,對Spring Data JPA 整合QueryDSL使用案例感興趣的朋友跟隨小編一起看看吧
    2023-08-08
  • java利用Ant腳本生成war包全過程

    java利用Ant腳本生成war包全過程

    這篇文章主要為大家詳細(xì)介紹了java利用Ant腳本生成war包全過程,感興趣的朋友可以參考一下
    2016-03-03
  • IDEA項目重命名的操作

    IDEA項目重命名的操作

    這篇文章主要介紹了IDEA項目重命名的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java 多線程實例詳解(三)

    Java 多線程實例詳解(三)

    本文主要介紹 java 線程安全的知識,這里整理了相關(guān)資料及實現(xiàn)示例代碼,有興趣的小伙伴可以參考下
    2016-09-09

最新評論

诏安县| 城市| 延寿县| 出国| 乌海市| 大姚县| 崇州市| 牡丹江市| 龙游县| 德格县| 蚌埠市| 休宁县| 方城县| 娱乐| 浦东新区| 册亨县| 东阿县| 昭平县| 奉节县| 桂林市| 乌苏市| 泸水县| 瓦房店市| 炎陵县| 庆城县| 建昌县| 扎鲁特旗| 沈阳市| 大同县| 阜新| 旺苍县| 砚山县| 六盘水市| 曲周县| 华池县| 来凤县| 曲沃县| 耒阳市| 漾濞| 清丰县| 迁安市|