CodeGym /Java Blog /Toto sisi /Java的比較器類
John Squirrels
等級 41
San Francisco

Java的比較器類

在 Toto sisi 群組發布
你好!今天我們要談談比較對象。 Java 的比較器類 - 1 嗯……可是這個話題我們不是已經談過不止一次了嗎?:/ 我們知道==運算符是如何工作的,以及equals()hashCode()方法。比較有點不一樣。以前,我們很可能是指“檢查對像是否相等”。但是將對象相互比較的原因可能完全不同!其中最明顯的是排序。我想如果你被告知對數字或字符串進行排序ArrayList<>,你將能夠毫無問題地處理這個問題:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       String name1 = "Masha";
       String name2 = "Sasha";
       String name3 = "Dasha";

       List<String> names = new ArrayList<>();
       names.add(name1);
       names.add(name2);
       names.add(name3);

       Collections.sort(names);
       System.out.println(names);
   }
}
控制台輸出:

[Dasha, Masha, Sasha]
如果您還記得Collections類及其sort()方法,那就太好了!我想你在數字方面也不會有問題。這裡有一個更具挑戰性的任務:

public class Car {
  
   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }
  
   // ...getters, setters, toString()
  
}

import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);
      
       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);
   }
}
任務其實很簡單。我們有一個Car類和 3 個 Car 對象。請您對列表中的汽車進行排序好嗎?您可能會問,“它們應該如何排序?” 按名字?按生產年份?按最大速度?很好的問題。目前,我們不知道如何對Car對象進行排序。而且,很自然地,Java 也不知道這一點!當我們嘗試將對象列表傳遞Car給該Collections.sort()方法時,我們得到一個錯誤:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(20012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       // Compilation error!
       Collections.sort(cars);
   }
}
事實上,該語言如何知道如何對您編寫的類的對象進行排序?這取決於您的程序需要做什麼。我們必須以某種方式教 Java 比較這些對象。並按照我們想要的方式比較它們。Java 對此有一個特殊的機制:Comparable接口。為了以某種方式比較和排序我們的Car對象,類必須實現這個接口,它由一個方法組成compareTo()::

public class Car implements Comparable<Car> {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   @Override
   public int compareTo(Car o) {
       return 0;
   }

   // ...getters, setters, toString()

}
請注意我們指定了Comparable<Car>接口,而不僅僅是Comparable. 這是一個參數化接口,也就是說,我們必須指定具體的關聯類。原則上可以<Car>從界面中移除,但Object默認情況下會基於對象進行比較。代替方法compareTo(Car o),我們的類將有:

@Override
   public int compareTo(Object o) {
       return 0;
   }
當然,我們使用它更容易Car。在方法內部compareTo(),我們實現了比較汽車的邏輯。假設我們需要按製造年份對它們進行排序。您可能注意到該compareTo()方法返回一個int,而不是一個boolean。不要讓這讓你感到驚訝。當我們比較兩個對象時,有 3 種可能性:
  • а < b
  • a > b
  • a == b.
boolean只有 2 個值:true 和 false,這不適用於比較對象。有了int,一切都簡單多了。如果返回值為> 0,則a > b。如果的結果compareTo< 0,那麼a < b。並且,如果結果為== 0,則兩個對象相等:a == b。教我們的班級按製造年份對汽車進行分類很容易:

@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
但是這裡發生了什麼?我們獲取一個 Car 對象 ( this),獲取這輛車的製造年份,並從中減去另一輛汽車(與該對象進行比較的汽車)的製造年份。如果第一輛汽車的製造年份更大,該方法將返回一個int > 0. 這意味著this car >汽車o。相反,如果第二輛車的製造年份 ( о) 更大,則該方法將返回一個負數,這意味著o > this. 最後,如果它們相等,則該方法將返回0。這個簡單的機制已經足夠我們對Car對象集合進行排序了!您無需執行任何其他操作。一探究竟:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       // There was previously an error here
       Collections.sort(cars);
       System.out.println(cars);
   }
}
控制台輸出:

[Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310}, 
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350}, 
Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290}]
汽車按照我們想要的方式分類!:) Java 的比較器類 - 2我應該什麼時候使用Comparable?中實現的比較方法Comparable稱為自然排序。這是因為在compareTo()方法中,您定義了比較此類對象的最常見或最自然的方式。Java 已經有了自然順序。例如,Java 知道字符串通常按字母順序排序,而數字則按數值遞增排序。因此,如果您sort()在數字或字符串列表上調用該方法,它們將被排序。如果我們的程序通常按製造年份對汽車進行比較和排序,那麼我們應該使用接口Comparable<Car>compareTo()方法。但是,如果這對我們來說還不夠怎麼辦?假設我們的程序不是那麼簡單。在大多數情況下,汽車的自然分類(我們已將其設置為按製造年份執行)適合我們。但有時我們的客戶是快速駕駛的狂熱愛好者。如果我們正在準備一份汽車目錄供他們閱讀,那麼汽車應該按最高速度排序。 Java 的比較器類 - 3例如,假設我們有 15% 的時間需要這樣排序。這顯然不足以讓我們將Car班級的自然排序設置為按速度而不是按製造年份。但是我們不能忽視15%的客戶。那麼我們該怎麼辦?另一個接口在這里為我們提供幫助:Comparator。就像Comparable,它是一個參數化的接口。有什麼不同? Comparable使我們的對象“可比較”並定義它們最自然的排序順序,即在大多數情況下將使用的排序順序。 Comparator是一個單獨的“比較”界面。如果我們需要實現某種特殊的排序順序,我們不需要深入到類中去Car改變.class的邏輯compareTo()。相反,我們可以創建一個單獨的類來實現 Comparator 並教它如何執行我們需要的排序!

import java.util.Comparator;

public class MaxSpeedCarComparator implements Comparator<Car> {
  
   @Override
   public int compare(Car o1, Car o2) {
       return o1.getMaxSpeed() - o2.getMaxSpeed();
   }
}
如您所見,我們的Comparator非常簡單。我們只需要實現一個接口方法:compare(). 它以兩個Car對像作為輸入,並以通常的方式(通過減法)比較它們的最大速度。like compareTo(),返回an int,比較的原理是一樣的。我們如何使用它?一切都很簡單:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       Comparator speedComparator = new MaxSpeedCarComparator();
       Collections.sort(cars, speedComparator);

       System.out.println(cars);
   }
}
控制台輸出:

[Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290}, 
Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310}, 
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350}]
Collections.sort()我們只需創建一個比較器對象並將其與要排序的列表一起 傳遞給方法。當sort()方法接收比較器時,它不使用CarcompareTo()方法中定義的自然排序。相反,它應用由傳遞給它的比較器定義的排序算法。 這樣做有什麼好處?首先,與現有代碼的兼容性。我們創建了一種新的特殊排序方法,同時保留了大部分時間都會使用的現有方法。Car我們根本就沒碰過課。它是一個Comparable,所以它仍然是:

public class Car implements Comparable<Car> {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   @Override
   public int compareTo(Car o) {
       return this.getManufactureYear() - o.getManufactureYear();
   }

   // ...getters, setters, toString()

}
第二,靈活性。我們可以添加任意多的排序算法。例如,我們可以按顏色、速度、重量或汽車在蝙蝠俠電影中的使用次數對汽車進行分類。我們需要做的就是創建一個額外的Comparator. 就是這樣!今天你學習了兩個非常重要的機制,你在工作中會經常在實際項目中使用它們。但是,如您所知,沒有實踐的理論是無用的。現在是時候鞏固您的知識並完成一些任務了!
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION