一、問題引入
使用集合工具類Collections的sort方法對集合内部元素排序,當存儲Integer類型資料時,程式的編譯、運作均正常,但當集合存儲自定義類型時,編譯器報錯,顯示未實作Comparable接口,如圖所示:
自定義類型 Person:
package cn.GTMStudio.Comparator;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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 String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
那麼這個Comparable是什麼呢?
二、Comparable接口
- Comparable 在 java.lang 包下,是一個接口,内部隻有一個方法 compareTo():
public interface Comparable<T> {
public int compareTo(T o);
}
- public interface Comparable<> 此接口強行對實作它的每個類的對象進行整體排序。這種排序被稱為類的自然排序,類的compareTo方法被稱為它的自然比較方法。
- 實作此接口的對象清單(和數組)可以通過 Collections.sort(和 Arrays.sort)進行自動排序。實作此接口的對象可以用作有序映射中的鍵或有序集合中的元素,無需指定比較器。
- Comparable的排序規則:this-參數為升序,反之則為降序。
觀察一下Integer的源碼發現integer實作了Comparable接口,并重寫了compareTo接口
實作Comparable接口
package cn.GTMStudio.Comparator;
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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 String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重寫Comparable接口的方法
@Override
public int compareTo(Person o) {
//Comparable排序規則:this-參數為升序,反之則為降序
return this.age-o.age;
}
}
再次運作程式,結果顯示正常,集合元素升序列印
三、Comparator比較器
試想這樣一種情況,某個自定義類型沒有實作Comparable接口,同時你無法修改該自定義類型,但是你必須要對集合元素進行排序,此時該怎麼辦呢?可以使用Comparator接口,該接口也稱為比較器。
- 從上面内容可知使用自然排序需要類實作 Comparable,并且在内部重寫 comparaTo 方法。
- Comparator 則是在外部制定排序規則,然後作為排序政策參數傳遞給某些類,比如 Collections.sort(), Arrays.sort(), 或者一些内部有序的集合(比如 SortedSet,SortedMap 等)。
- 使用方式主要分三步:
- 建立一個 Comparator 接口的實作類,并指派給一個對象
- 在 compare 方法中針對自定義類寫排序規則
- 将 Comparator 對象作為參數傳遞給 排序類的某個方法,向排序類中添加 compare 方法中使用的自定義類
建立Stdent類
package cn.GTMStudio.Comparator;
public class Student {
private String name;
private int id;
public Student() {
}
public Student(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
實作Comparator接口,定制外部排序規則
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按學号升序排列
int result = o1.getId() - o2.getId();
if (result==0){
//如果學号相同,則按名字首字母降序排列
result=o2.getName().charAt(0)-o1.getName().charAt(0);
}
return result;
}
});
運作結果
四、總結
Java 中的兩種排序方式:
- Comparable 自然排序。(實體類實作)
- Comparator 是定制排序。(無法修改實體類時,直接在調用方建立)
- 同時存在時采用 Comparator(定制排序)的規則進行比較
對于一些普通的資料類型(比如 String, Integer, Double…),它們預設實作了Comparable 接口,實作了 compareTo 方法,我們可以直接使用。
而對于一些自定義類,它們可能在不同情況下需要實作不同的比較政策,我們可以新建立 Comparator 接口,然後使用特定的 Comparator 實作進行比較。