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

練習:

存儲學生對象並遍歷,創建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

Tags: