Java思考——如何使用Comparable按照我們指定的規則排序?

来源:https://www.cnblogs.com/CYan521/archive/2022/03/29/16073112.html
-Advertisement-
Play Games

練習: 存儲學生對象並遍歷,創建TreeSet集合使用無參構造方法,並按照年齡從小到大的順序排序,若年齡相同再按照姓名的字母順序排序 分析: 1.創建學生類,成員變數name,age;無參構造,帶參構造;get\set方法; 2.創建測試類,添加數據併進行排序;直接排序會報錯 3.需要Student ...


練習:

存儲學生對象並遍歷,創建TreeSet集合使用無參構造方法,並按照年齡從小到大的順序排序,若年齡相同再按照姓名的字母順序排序

分析:

1.創建學生類,成員變數name,age;無參構造,帶參構造;get\set方法;

2.創建測試類,添加數據併進行排序;直接排序會報錯

3.需要Student實現comparable介面並重寫Comparable中的compareto方法來實現按照我們給定的順序排序

Student類代碼

public class Student{
  //成員變數
  private String name;
  private int age;
  //構造方法
  public Student(){}
  public Student(String name,int age){
      this.age=age;
      this.name=name;
  }
  //get\set方法

  public String getName() {
      return name;
  }

  public void setName(String name) {
      this.name = name;
  }

  public int getAge() {
      return age;
  }

  public void setAge(int age) {
      this.age = age;
  }
}

測試類

public class StudentDemo {
  public static void main(String[] args) {
      //創建TreeSet對象
      TreeSet<Student>ts=new TreeSet<Student>();
      //創建學生對象
      Student s=new Student("張三",18);
      Student s1=new Student("張四",17);
      Student s2=new Student("張五",19);
      Student s3=new Student("張六",12);
      //添加數據
      ts.add(s);
      ts.add(s1);
      ts.add(s2);
      ts.add(s3);
      //遍歷
      for (Student ss:ts){
          System.out.println(ss.getName()+ss.getAge());
      }
  }

}

第一次運行結果提示Student cannot be cast to java.lang.Comparable,這個時候我們就需要在Student類實現comparable介面重寫compareto方法,並給定返回值

public class Student implements Comparable<Student>{
  //成員變數
  private String name;
  private int age;
  //構造方法
  public Student(){}
  public Student(String name,int age){
      this.age=age;
      this.name=name;
  }
  //get\set方法

  public String getName() {
      return name;
  }

  public void setName(String name) {
      this.name = name;
  }

  public int getAge() {
      return age;
  }

  public void setAge(int age) {
      this.age = age;
  }

  @Override
  public int compareTo(Student o) {
  //     return 0;
  //     return 1;
  //     return-1;
  }
}

那麼可以看到compareto方法中有三個返回值分別是0、1、-1三種情況;

1.return 0:返回值是0的情況下再遍歷集合只會在控制台列印出第一個元素;這是因為存入第一個元素時不需要比較直接存入集合,第二個 元素再存入是就需要跟第一個元素比較,但返回值為0,就會認為第二個元素跟第一個元素是相同的、重覆的,就不存儲,依此類推

2.return 1:返回值是1的情況下再遍歷集合會按照存儲數據的順序在控制台全部列印出來;同樣的,第一個元素存入不比較,第二個元素與第一個元素比較,返回值為1;就會認為第二個元素比第一個元素大,排在第一個元素後面,以此類推

3.return -1:與renturn 1的情況相反,也就是會按照存儲數據順序的倒序方式在控制台列印出來

思考:我們需要按照年齡的大小排序,這本質上不是只要返回值是一個正數就行了嘛,那我們就可以在compareto方法中這樣寫

public int compareTo(Student s) {
      //return 0;
      //return 1;
      int num=this.age-s.age;
      return num;
  }

其中,this是方法內部就有的,在這裡this.age代表當第一個元素存儲後的後續每一個元素的年齡,我們用後續存儲的元素年齡減去第一個元素的年齡當結果是-1時,就將該元素排在第一個元素前面,為1時,就排在後面,為0時就代表重覆不存儲

但是在我們完成按照年齡進行排序後有出現一個問題:當兩個元素姓名不同年齡相同時,再按照我們設定的規則就不會將年齡相同的最後一個元素存儲進去,因為它們兩個年齡相減為0,預設重覆了。所以在年齡相同的情況下,我們還要再比較姓名,如下

   public int compareTo(Student s) {
      //return 0;
      //return 1;
      int num=this.age-s.age;
      int num1=num==0?this.name.compareTo(s.name):num;
      return num1;

  }

當年齡不同時返回的還是之前num的值,當年齡相同時比較姓名是否相同不相同返回1代表可以進行存儲,相同返回0代表重覆。

在這裡因為string 本身就實現了comparable介面,所以可以直接調用compareto方法,這樣就很好的解決了問題又保證了數據的唯一性

總結:

1.TreeSet集合存儲自定義對象時,無參構造方法使用的是自然排序也就是按照存儲元素的順序進行排序

2.自然排序也就是讓元素所屬的類實現Comparable介面,重寫compareto(T o)方法

3.重寫compareto(T o)方法時,一定要註意排序規則必須按照要求的主要條件和次要條件來寫

 

 

比較器排序Comparator

練習:

存儲學生對象並遍歷,創建TreeSet集合使用帶參構造方法,並按照年齡從小到大的順序排序,若年齡相同再按照姓名的字母順序排序

分析:較於comparable來說,comparator無需在Student類中實現comparable介面,可以直接在創建TreeSet集合對象時使用內部類的方式進行

public class StudentDemo {
  public static void main(String[] args) {
      //創建TreeSet對象
      TreeSet<Student>ts=new TreeSet<Student>(new Comparator<Student>() {
          @Override
          public int compare(Student s1, Student s2) {
              int num =s1.getAge()-s2.getAge();
              int num1=num==0?s1.getName().compareTo(s2.getName()):num;
              return num1;
          }
      });
      //創建學生對象
      Student s=new Student("張三",18);
      Student s1=new Student("張四",17);
      Student s2=new Student("張五",19);
      Student s3=new Student("張六",12);
      Student s4=new Student("張七",12);
      //添加數據
      ts.add(s);
      ts.add(s1);
      ts.add(s2);
      ts.add(s3);
      ts.add(s4);
      for (Student ss:ts){
          System.out.println(ss.getName()+ss.getAge());
      }
  }

}

其中需要註意的是,compare方法傳遞了兩個參數,s1就等同於compareto中的this,但由於內部類無法直接訪問Student類的私有成員變數,只能通過get方式來獲取,效果等同於自然排序Comparable

感謝1樓前輩給出的指導,文中出現的錯誤與更正如下:

1.TreeSet集合存儲自定義對象時,無參構造方法使用的是自然排序也就是按照存儲元素的順序進行排序) 正確的總結:使用TreeSet時,要麼實現Comparable介面,要麼指定Comparator,兩者並存時優先使用Comparator。否則add方法報錯cannot be cast to java.lang.Comparable

可以在TreeMap中找到源碼:

/**
* Compares two keys using the correct comparison method for this TreeMap.
*/
@SuppressWarnings("unchecked")
final int compare(Object k1, Object k2) {
   return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
      : comparator.compare((K)k1, (K)k2);
}
// Student未實現Comparable介面時,初始化TreeSet時,需指定Comparator
TreeSet<Student> ts2 = new TreeSet<>(Comparator.comparingInt(Student::getAge).thenComparing(Student::getName));
ts.add(new Student("張三", 18));

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 實戰項目地址newbeemall,集成RediSearch,代碼開源已上傳,支持的話可以點個star😁 RediSearch 是基於 Redis 開發的支持二級索引、查詢引擎和全文搜索的應用程式。在2.0的版本中,簡單看下官網測試報告: 索引構建 在索引構建測試中,RediSearch 用221秒 ...
  • 思路: * A:創建一個HashMap集合 * B:創建一個ArrayList集合 * C:創建花色數組和點數數組 * D:從0開始往HashMap裡面存儲編號,並存儲對應的牌 * 同時往ArrayList裡面存儲編號即可。 * E:洗牌(洗的是編號) * F:發牌(發的也是編號,為了保證編號是排序 ...
  • 《獵罪圖鑒》可以說是國產懸疑劇之光了,上線首周熱度不斷飆升。該劇講述了因一起塵封舊案而結怨的模擬畫像師沈翊和刑警隊長杜城,在機緣巧合下被迫搭檔,兩人聯手偵破多起離奇疑案,共同追蹤謎底真相的故事。今天就用Python爬取該劇彈幕,做詞雲圖 環境介紹 python 3.8pycharmrequests ...
  • 圖論 圖論是數學的一個分支。它以圖為研究對象。圖論中的圖是由若幹給定的點及連接兩點的線所構成的圖形,這種圖形通常用來描述某些事物之間的某種特定關係,用點代表事物,用連接兩點的線表示相應兩個事物間具有這種關係。 樹 樹是一種數據結構,它是由n(n≥1)個有限節點組成一個具有層次關係的集合。把它叫做“樹 ...
  • 任務要求 把棋盤當作一個稀疏矩陣,0表示沒棋,1表示黑棋,2表示藍棋。 把該稀疏矩陣壓縮以三元組形式表示並以文件形式保存,再寫另一個程式讀取文件中的信息把壓縮後的三元組還原成原來的稀疏矩陣。 其中三元組的第一行用來存儲原始稀疏矩陣的行數、列數和有效的數據個數,其餘行用來存儲有效的非0數據 思路分析 ...
  • 前言 開發環境 python 3.8pycharm 2021.2 專業版 代碼實現 發送請求 獲取數據 解析數據(篩選數據) 保存數據 連接資料庫 對於本篇文章有疑問的同學可以加【資料白嫖、解答交流群:910981974】 開始代碼 請求數據 # 偽裝 headers = { 'cookie': ' ...
  • 一個簡單的Java程式 // HelloJava.java public class HelloJava { public static void main(String[] args) { System.out.println("Hello Java!"); } } Java是區分大小寫的 關鍵字 ...
  • finally的特點 finally:被finally控制的語句體一定會執行 * 註意:如果在執行到finally之前jvm退出了,就不能執行了。 * * A:格式 * try...catch...finally... * B:用於釋放資源,在IO流操作和資料庫操作中會見到 package cn.i ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...