在業務邏輯中,我們經常需要對list進行排序,就像下面這樣:
Collections.sort(l);
如果l中的元素是String類型,你會發現sort方法將使用字母順序排序。如果l中的元素是Date類型,sort方法將使用日歷順序排序。這是因為String和Date都實現了Comparable接口,也就是說,如果你想對某種對象進行排序,那么它必須實現Comparable接口。在Java語言中,實現該接口的類羅列如下:
Class | Natural Ordering |
---|---|
Byte |
Signed numerical |
Character |
Unsigned numerical |
Long |
Signed numerical |
Integer |
Signed numerical |
Short |
Signed numerical |
Double |
Signed numerical |
Float |
Signed numerical |
BigInteger |
Signed numerical |
BigDecimal |
Signed numerical |
Boolean |
Boolean.FALSE < Boolean.TRUE |
File |
System-dependent lexicographic on path name |
String |
Lexicographic |
Date |
Chronological |
CollationKey |
Locale-specific lexicographic |
如果某個類是別人寫的,它確實沒有實現該接口,那就對排序問題無能為力了么?不是的,sort還有另一種形式:
Collections.sort(list, comparator)
只有這兩種方法。如果以上兩種方法你都沒有做,那么sort方法將拋出異常。
Comparable接口
Comparable接口形式如下:
public interface Comparable<T> { public int compareTo(T o); }
是的,它只有一個方法。你必須在該方法中定義對象是如何比較的。下面是一個demo:
SortDemo.java
package Colloections; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class SortDemo { public static void main(String[] args) { // TODO Auto-generated method stub new SortDemo().sort(); } private void sort(){ Person p1 = new Person("bob", 5); Person p2 = new Person("albert", 8); Person p3 = new Person("bob", 13); List<Person> list = new ArrayList<Person>(); list.add(p1); list.add(p2); list.add(p3); System.out.printf("排序前:%n"); for (Person person : list) { System.out.printf(person.toString()); } Collections.sort(list); System.out.printf("排序后:%n"); for (Person person : list) { System.out.printf(person.toString()); } } } class Person implements Comparable<Person>{ public String name; public int age; public Person(String n, int a){ name = n; age = a; } public String toString() { return String.format("Name is %s, Age is %d%n", name, age); } @Override public int compareTo(Person o) { // TODO Auto-generated method stub //排序優先級為:姓名/年齡 int nameComp = this.name.compareTo(o.name); return (nameComp != 0 ? nameComp : (this.age - o.age)); } }
程序輸出如下:
排序前:
Name is bob, Age is 5
Name is albert, Age is 8
Name is bob, Age is 13
排序后:
Name is albert, Age is 8
Name is bob, Age is 5
Name is bob, Age is 13
Comparator
Comparator接口提供一個獨立的排序功能,這有兩個用處:1.你不想使用某個類自帶的compareTo邏輯進行排序;2.某個類並沒有繼承Comparable接口。可見,Comparator接口使得排序更加靈活。它的形式如下所示:
public interface Comparator<T> { int compare(T o1, T o2); }
是的,一個方法就夠了。當o1比o2小於,等於,大於時,compare方法將返回一個負數,零或者正數。使用demo如下:
SortDemo.java
package Colloections; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class SortDemo { public static void main(String[] args) { // TODO Auto-generated method stub //new SortDemo().sort(); new SortDemo().sortByComparatpr(); } private void sortByComparatpr(){ Person p1 = new Person("bob", 5); Person p2 = new Person("albert", 8); Person p3 = new Person("bob", 13); List<Person> list = new ArrayList<Person>(); list.add(p1); list.add(p2); list.add(p3); System.out.printf("排序前:%n"); for (Person person : list) { System.out.printf(person.toString()); } PersonComparator comparator = new PersonComparator(); Collections.sort(list, comparator); System.out.printf("排序后:%n"); for (Person person : list) { System.out.printf(person.toString()); } } private void sort(){ Person p1 = new Person("bob", 5); Person p2 = new Person("albert", 8); Person p3 = new Person("bob", 13); List<Person> list = new ArrayList<Person>(); list.add(p1); list.add(p2); list.add(p3); System.out.printf("排序前:%n"); for (Person person : list) { System.out.printf(person.toString()); } Collections.sort(list); System.out.printf("排序后:%n"); for (Person person : list) { System.out.printf(person.toString()); } } } class Person implements Comparable<Person>{ public String name; public int age; public Person(String n, int a){ name = n; age = a; } public String toString() { return String.format("Name is %s, Age is %d%n", name, age); } @Override public int compareTo(Person o) { // TODO Auto-generated method stub //排序優先級為:姓名/年齡 int nameComp = this.name.compareTo(o.name); return (nameComp != 0 ? nameComp : (this.age - o.age)); } } class PersonComparator implements Comparator<Person>{ @Override public int compare(Person o1, Person o2) { // TODO Auto-generated method stub return o2.compareTo(o1); } }
程序輸出如下:
排序前:
Name is bob, Age is 5
Name is albert, Age is 8
Name is bob, Age is 13
排序后:
Name is bob, Age is 13
Name is bob, Age is 5
Name is albert, Age is 8
注意,這里的輸出是降序排列的,因為在compare方法中使用o2與o1進行了比較。如果需要升序排列,則如下修改即可:
return o1.compareTo(o2);
注意,不要這樣修改:
return -o2.compareTo(o1);
這是因為compareTo返回的負數值是不確定的,而有一個特殊的負整數,取負時結果仍為負數:
-Integer.MIN_VALUE == Integer.MIN_VALUE