在业务逻辑中,我们经常需要对list进行排序,就像下面这样:
Collections.sort(l);
如果l中的元素是String类型,你会发现sort方法将使用字母顺序排序。如果l中的元素是Date类型,sort方法将使用日历顺序排序。这是因为String和Date都实现了Comparable接口,也就是说,如果你想对某种对象进行排序,那么它必须实现Comparable接口。在Java语言中,实现该接口的类罗列如下:
Classes Implementing Comparable
ClassNatural 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 {
public int compareTo(T o);
}
是的,它只有一个方法。你必须在该方法中定义对象是如何比较的。下面是一个demo:
SortDemo.java
packageColloections;importjava.util.ArrayList;importjava.util.Collections;importjava.util.Comparator;importjava.util.List;public classSortDemo {public static voidmain(String[] args) {//TODO Auto-generated method stubnew SortDemo().sort();}private voidsort(){
Person p1= new Person("bob", 5);
Person p2= new Person("albert", 8);
Person p3= new Person("bob", 13);
List list = new ArrayList();
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{publicString name;public intage;public Person(String n, inta){
name=n;
age=a;
}publicString toString() {return String.format("Name is %s, Age is %d%n", name, age);
}
@Overridepublic intcompareTo(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{intcompare(T o1, T o2);
}
是的,一个方法就够了。当o1比o2小于,等于,大于时,compare方法将返回一个负数,零或者正数。使用demo如下:
SortDemo.java
packageColloections;importjava.util.ArrayList;importjava.util.Collections;importjava.util.Comparator;importjava.util.List;public classSortDemo {public static voidmain(String[] args) {//TODO Auto-generated method stub//new SortDemo().sort();
newSortDemo().sortByComparatpr();
}private voidsortByComparatpr(){
Person p1= new Person("bob", 5);
Person p2= new Person("albert", 8);
Person p3= new Person("bob", 13);
List list = new ArrayList();
list.add(p1);
list.add(p2);
list.add(p3);
System.out.printf("排序前:%n");for(Person person : list) {
System.out.printf(person.toString());
}
PersonComparator comparator= newPersonComparator();
Collections.sort(list, comparator);
System.out.printf("排序后:%n");for(Person person : list) {
System.out.printf(person.toString());
}
}private voidsort(){
Person p1= new Person("bob", 5);
Person p2= new Person("albert", 8);
Person p3= new Person("bob", 13);
List list = new ArrayList();
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{publicString name;public intage;public Person(String n, inta){
name=n;
age=a;
}publicString toString() {return String.format("Name is %s, Age is %d%n", name, age);
}
@Overridepublic intcompareTo(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{
@Overridepublic intcompare(Person o1, Person o2) {//TODO Auto-generated method stub
returno2.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