Java-对象排序

时间:2022-03-14 09:18:03

在业务逻辑中,我们经常需要对list进行排序,就像下面这样:

Collections.sort(l);

如果l中的元素是String类型,你会发现sort方法将使用字母顺序排序。如果l中的元素是Date类型,sort方法将使用日历顺序排序。这是因为String和Date都实现了Comparable接口,也就是说,如果你想对某种对象进行排序,那么它必须实现Comparable接口。在Java语言中,实现该接口的类罗列如下:

Classes Implementing Comparable
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