JavaRush /Java Blog /Random-TW /Java 中的比較器

Java 中的比較器

在 Random-TW 群組發布
你好!今天我們將討論比較對象。嗯……不過這個問題我們好像已經討論過不只一次了?:/ 我們知道「==」運算子如何運作,以及equals()and方法hashCode()。比較並不是真的。以前,我們的意思更像是「測試對象的平等性」。Java 中的比較器 - 1但相互比較物件可能有完全不同的目標!最明顯的就是排序。我認為如果你被告知對數字或字串列表進行排序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 = "Даша";

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

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

[Даша, Маша, Саша]
如果您還記得該類別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;
   }

   //...геттеры, сеттеры, 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。而且,很自然地,Java 也不知道這一點!當我們嘗試將Collections.sort()物件列表傳遞給方法時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(20012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

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

       //ошибка компилятора!
       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;
   }

   //...геттеры, сеттеры, 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是的話а < b。好吧,如果結果是== 0,那麼這兩個物件是相等的:a == b。教導我們的班級按製造年份對汽車進行分類就像剝梨子一樣簡單:
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
這裡發生了什麼事?我們取得一個汽車物件 ( this),即該汽車的製造年份,並從中減去另一輛車(我們與該物件進行比較的汽車)的製造年份。如果第一輛汽車的製造年份更大,則該方法將返回int > 0。這意味著汽車this >就是汽車о。相反,如果第二輛汽車的製造年份 ( о) 更大,則該方法將返回負數,因此о > 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);

       //тут раньше была ошибка
       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並改變邏輯compareTo()。相反,我們可以在程式中創建一個單獨的比較器類,並教它進行我們需要的排序!
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()——這是一個介面方法Comparator,必須實現它。它以兩個物體作為輸入Car,並以通常的方式(透過減法)比較它們的最大速度。就像compareTo(),它返回數字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()中定義的自然排序。相反,它將應用傳遞給它的比較器中的排序演算法。這為我們帶來了什麼好處?首先,與書面程式碼的兼容性。我們創建了一種新的、特定的排序方法,同時保留了目前的排序方法,該方法將在大多數情況下使用。我們根本沒有接觸過班級。他還是原來的樣子: compareTo()CarCarComparable
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();
   }

   //...геттеры, сеттеры, toString()

}
其次,靈活性。我們可以根據需要添加任意數量的種類。比如說,按顏色、速度、重量或汽車在蝙蝠俠電影中使用的次數對汽車進行排序。只需再創建一個就足夠了Comparator。就這樣!今天您學習了兩個非常重要的機制,您將在實際工作項目中經常使用它們。但是,如您所知,沒有實踐的理論毫無意義。因此,是時候鞏固你的知識並解決幾個問題了!:)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION