在业务逻辑中,我们经常需要对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