Java 高階排序(Comparator 和 Comparable)
Java 高階排序
在 列表排序章節 中,您學習瞭如何按字母順序和數字順序對列表進行排序,但如果列表中包含物件呢?
要對物件進行排序,您需要指定一個決定物件如何排序的規則。例如,如果您有一系列汽車,您可能希望按年份對它們進行排序,規則可以是較早年份的汽車在前。
Comparator
和 Comparable
介面允許您指定用於對物件進行排序的規則。
能夠指定排序規則也允許您更改字串和數字的排序方式。
Comparators(比較器)
實現 Comparator
介面的物件稱為比較器。
Comparator
介面允許您建立一個具有 compare()
方法的類,該方法比較兩個物件以決定哪個物件在列表中應該排在前面。
compare()
方法應返回一個數字,該數字是
- 負數,如果第一個物件應該排在列表前面。
- 正數,如果第二個物件應該排在列表前面。
- 零,如果順序無關緊要。
實現 Comparator
介面的類可能看起來像這樣
// Sort Car objects by year
class SortByYear implements Comparator {
public int compare(Object obj1, Object obj2) {
// Make sure that the objects are Car objects
Car a = (Car) obj1;
Car b = (Car) obj2;
// Compare the objects
if (a.year < b.year) return -1; // The first car has a smaller year
if (a.year > b.year) return 1; // The first car has a larger year
return 0; // Both cars have the same year
}
}
要使用比較器,請將其作為引數傳遞給排序方法
// Use a comparator to sort the cars
Comparator myComparator = new SortByYear();
Collections.sort(myCars, myComparator);
以下是使用比較器按年份對汽車列表進行排序的完整示例
示例
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
// Define a Car class
class Car {
public String brand;
public String model;
public int year;
public Car(String b, String m, int y) {
brand = b;
model = m;
year = y;
}
}
// Create a comparator
class SortByYear implements Comparator {
public int compare(Object obj1, Object obj2) {
// Make sure that the objects are Car objects
Car a = (Car) obj1;
Car b = (Car) obj2;
// Compare the year of both objects
if (a.year < b.year) return -1; // The first car has a smaller year
if (a.year > b.year) return 1; // The first car has a larger year
return 0; // Both cars have the same year
}
}
public class Main {
public static void main(String[] args) {
// Create a list of cars
ArrayList<Car> myCars = new ArrayList<Car>();
myCars.add(new Car("BMW", "X5", 1999));
myCars.add(new Car("Honda", "Accord", 2006));
myCars.add(new Car("Ford", "Mustang", 1970));
// Use a comparator to sort the cars
Comparator myComparator = new SortByYear();
Collections.sort(myCars, myComparator);
// Display the cars
for (Car c : myCars) {
System.out.println(c.brand + " " + c.model + " " + c.year);
}
}
}
自己動手試一試 »
使用 Lambda 表示式
為了使程式碼更短,比較器可以用 lambda 表示式替換,該表示式具有與 compare()
方法相同的引數和返回值
示例
使用 lambda 表示式作為比較器
Collections.sort(myCars, (obj1, obj2) -> {
Car a = (Car) obj1;
Car b = (Car) obj2;
if (a.year < b.year) return -1;
if (a.year > b.year) return 1;
return 0;
});
自己動手試一試 »
特殊排序規則
比較器還可以用於為字串和數字建立特殊的排序規則。在此示例中,我們使用比較器將所有偶數排在奇數之前
示例
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
class SortEvenFirst implements Comparator {
public int compare(Object obj1, Object obj2) {
// Make sure the objects are integers
Integer a = (Integer)obj1;
Integer b = (Integer)obj2;
// Check each number to see if it is even
// A number is even if the remainder when dividing by 2 is 0
boolean aIsEven = (a % 2) == 0;
boolean bIsEven = (b % 2) == 0;
if (aIsEven == bIsEven) {
// If both numbers are even or both are odd then use normal sorting rules
if (a < b) return -1;
if (a > b) return 1;
return 0;
} else {
// If a is even then it goes first, otherwise b goes first
if (aIsEven) {
return -1;
} else {
return 1;
}
}
}
}
public class Main {
public static void main(String[] args) {
ArrayList<Integer> myNumbers = new ArrayList<Integer>();
myNumbers.add(33);
myNumbers.add(15);
myNumbers.add(20);
myNumbers.add(34);
myNumbers.add(8);
myNumbers.add(12);
Comparator myComparator = new SortEvenFirst();
Collections.sort(myNumbers, myComparator);
for (int i : myNumbers) {
System.out.println(i);
}
}
}
自己動手試一試 »
Comparable 介面
Comparable
介面允許物件透過 compareTo()
方法指定其自身的排序規則。
compareTo()
方法接受一個物件作為引數,並將可比較物件與該引數進行比較,以決定哪個物件在列表中應該排在前面。
與比較器一樣,compareTo()
方法返回一個數字,該數字是
- 負數,如果可比較物件應該排在列表前面。
- 正數,如果另一個物件應該排在列表前面。
- 零,如果順序無關緊要。
許多原生的 Java 類都實現了 Comparable
介面,例如 String
和 Integer
。
這就是為什麼字串和數字不需要比較器就可以排序的原因。
實現 Comparable
介面的物件可能看起來像這樣
class Car implements Comparable {
public String brand;
public String model;
public int year;
// Decide how this object compares to other objects
public int compareTo(Object obj) {
Car other = (Car)obj;
if(year < other.year) return -1; // This object is smaller than the other one
if(year > other.year) return 1; // This object is larger than the other one
return 0; // Both objects are the same
}
}
這是與之前相同的示例,但使用了 Comparable
介面而不是比較器
示例
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
// Define a Car class which is comparable
class Car implements Comparable {
public String brand;
public String model;
public int year;
public Car(String b, String m, int y) {
brand = b;
model = m;
year = y;
}
// Decide how this object compares to other objects
public int compareTo(Object obj) {
Car other = (Car)obj;
if(year < other.year) return -1; // This object is smaller than the other one
if(year > other.year) return 1; // This object is larger than the other one
return 0; // Both objects are the same
}
}
public class Main {
public static void main(String[] args) {
// Create a list of cars
ArrayList<Car> myCars = new ArrayList<Car>();
myCars.add(new Car("BMW", "X5", 1999));
myCars.add(new Car("Honda", "Accord", 2006));
myCars.add(new Car("Ford", "Mustang", 1970));
// Sort the cars
Collections.sort(myCars);
// Display the cars
for (Car c : myCars) {
System.out.println(c.brand + " " + c.model + " " + c.year);
}
}
}
自己動手試一試 »
一個常見的排序技巧
最自然地對兩個數字進行排序的方法是像這樣寫
if(a.year < b.year) return -1; // a is less than b
if(a.year > b.year) return 1; // a is greater than b
return 0; // a is equal to b
但實際上可以用一行程式碼完成
return a.year - b.year;
這個技巧也可以用來輕鬆地反向排序
return b.year - a.year;
Comparator 與 Comparable 的區別
比較器是一個只有一個方法且用於比較兩個不同物件 Object。
可比較物件是其本身可以與其它物件進行比較的物件。
如果可能,使用 Comparable
介面會更容易,但 Comparator
介面功能更強大,因為它允許您對任何型別的物件進行排序,即使您無法更改其程式碼。