你好!今天我們將討論比較對象。嗯……不過這個問題我們好像已經討論過不只一次了?:/ 我們知道「
==
」運算子如何運作,以及equals()
and方法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 = "Даша";
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}]
汽車按其應有的方式分類!:) 在什麼情況下應該使用它Comparable
?所實現的比較方法Comparable
稱為「自然排序」。這是因為在該方法中compareTo()
,您描述了將用於程式中此類別的物件最常見的比較方法。Java 中已經存在自然排序。例如,Java 知道字串通常按字母順序排序,數字通常按升序排序。因此,如果您對數字或字串清單呼叫該方法sort()
,它們將會被排序。如果在我們的程式中,汽車在大多數情況下將按製造年份進行比較和排序,那麼值得使用介面Comparable<Car>
和方法為它們定義自然排序compareTo()
。但如果這對我們來說還不夠呢?想像一下我們的程式沒那麼簡單。在大多數情況下,汽車的自然分類(我們按製造年份設定)適合我們。但有時我們的客戶中也有一些喜歡快速駕駛的人。如果我們準備一份汽車目錄供他們選擇,則需要以最高速度訂購。 例如,我們在 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()
Car
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();
}
//...геттеры, сеттеры, toString()
}
其次,靈活性。我們可以根據需要添加任意數量的種類。比如說,按顏色、速度、重量或汽車在蝙蝠俠電影中使用的次數對汽車進行排序。只需再創建一個就足夠了Comparator
。就這樣!今天您學習了兩個非常重要的機制,您將在實際工作項目中經常使用它們。但是,如您所知,沒有實踐的理論毫無意義。因此,是時候鞏固你的知識並解決幾個問題了!:)
GO TO FULL VERSION