Collections.sort()
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
Collections.sort()的源码如上所示,可以看到Collections.sort()实现了两种重载:
- 第一种
<T extends Comparable<? super T>>
:这种方法需要我们实现Comparable接口中的compareTo()
方法 - 第二种对泛型无要求,但是需要我们实现Comparator比较器接口
Comparable排序接口
- 如果一个类实现了Comparable接口,则该类支持排序
- 如果一个List或者一个数组中的对象是实现了Comparable接口的类,则可以通过
Collections.sort()
或者Arrays.sort()
来对该数组进行排序
可以通过一个例子来说明。首先我们创建一个类Fruit实现Comparable接口,并且重载compareTo方法:
class Fruit implements Comparable<Fruit>{
private String name;
private int price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public int compareTo(Fruit f) {
return this.price-f.price;
}
@Override
public String toString() {
return "the fruit is "+this.name+"\nand the price is "+this.price;
}
}
- 这个类中还重载了toString方法,这样我们可以通过
System.out.println(实体对象)
直接输出这个对象的信息 - 本来compareTo()是用于比较字符串的,这里重载之后用于比较int型数字
然后测试一下:
public static void main(String[] args) {
List<Fruit> list=new ArrayList<>();
Fruit apple=new Fruit();
apple.setName("apple");
apple.setPrice(12);
Fruit banana=new Fruit();
banana.setName("banana");
banana.setPrice(7);
list.add(apple);
list.add(banana);
Collections.sort(list);
System.out.println(list);
}
运行结果为:
可以看到,成功通过Collections.sort()对动态数组list中的中的两个对象apple和banana按照价格进行了升序排序。
PS:
如果我们需要实现升序排序,重载compareTo()方法时使用【成员变量-方法变量】的方式:
@Override
public int compareTo(Fruit f) {
return this.price-f.price;
}
如果需要实现降序排序,重载时使用【方法变量-成员变量】的方式:
@Override
public int compareTo(Fruit f) {
return this.price-f.price;
}
Comparator比较器接口
对刚刚那个例子,这次我们使用Comparator比较器接口来实现Collections.sort()来进行排序:
class Fruit{
private String price;
private String name;
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "the fruit name is "+name+"\nand the price is "+price;
}
}
首先可以看到第二种方法中,我们创建的类没有重载compareTo方法。测试方法如下:
public static void main(String[] args) {
List<Fruit> list=new ArrayList<>();
Fruit apple=new Fruit();
apple.setName("apple");
apple.setPrice("12");
Fruit banana=new Fruit();
banana.setName("banana");
banana.setPrice("7");
list.add(apple);
list.add(banana);
Collections.sort(list,new Comparator<Fruit>() {
@Override
public int compare(Fruit f1,Fruit f2) {
return f1.getPrice().compareTo(f2.getPrice());
}
});
System.out.println(list);
}
运行结果如下:
拓展一:Comparator比较器接口的另外一种写法
如果一个类对象有多种可以比较的参数,则可以使用自定义比较器来实现对不同参数的排序。
这里同样以刚刚的例子进行说明,令Fuit这个类的成员变量为id、name、price,然后针对Fruit对象的id和price来写自定义比较器来排序。
Fruit类代码如下:
class Fruit{
private int id;
private String name;
private int price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "id: "+id+" fruit name: "+name+" price: "+price;
}
}
- 使用自定义比较器接口的话,类就不用实现Comparable接口
- Fruit的成员变量有id、name、price,每个成员变量都有自己的set和get方法
- Fruit类重写了toString()方法
对id和price的自定义比较器如下:
static class PriceComparator implements Comparator<Object>{
public int compare(Object o1,Object o2) {
Fruit f1=(Fruit)o1;
Fruit f2=(Fruit)o2;
return f1.getPrice()-f2.getPrice();
}
}
static class IdComparator implements Comparator<Object>{
public int compare(Object o1,Object o2) {
Fruit f1=(Fruit)o1;
Fruit f2=(Fruit)o2;
return f1.getId()-f2.getId();
}
}
public static void printList(List<Fruit> list) {
Iterator it=list.iterator();
while(it.hasNext()) {
System.out.println(it.next()+"\n");
}
}
- 自定义比较器需要实现Comparator接口,同时实现了该接口中的方法compare()
- 这里还写了个方法printList,用于打印Fruit数组中的对象
测试方法如下:
public static void main(String[] args) {
List<Fruit> list=new ArrayList<>();
Fruit apple=new Fruit();
apple.setId(1);
apple.setName("apple");
apple.setPrice(12);
Fruit banana=new Fruit();
banana.setId(2);
banana.setName("banana");
banana.setPrice(7);
list.add(apple);
list.add(banana);
Collections.sort(list,new PriceComparator());
System.out.println("按照书的价格来排序"+"\n");
printList(list);
Collections.sort(list,new IdComparator());
System.out.println("按照书的ID来排序"+"\n");
printList(list);
}
运行结果如下:
拓展二:使用ES6的语法来写Comparator比较器接口
通过ES6的语法来写的话,代码看起来会简洁很多。例如我们有一个list,list是Fruit对象,现在使用Collections.sort()来对list中的Fruit对象按照id来排序。
首先我们的Fruit的代码为:
class Fruit{
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "id: "+String.valueOf(id)+"\nname: "+name+"\n";
}
}
然后测试类为:
public class TestComparator{
public static void main(String[] args) {
List<Fruit> list=new ArrayList<Fruit>();
Fruit apple=new Fruit();
apple.setId(0);
apple.setName("apple");
Fruit banana=new Fruit();
banana.setId(3);
banana.setName("banana");
list.add(apple);
list.add(banana);
Collections.sort(list,(a,b)->(a.getId()-b.getId()));
System.out.println(list);
}
}
可以发现,Collections.sort()的代码被缩减成了一行:
Collections.sort(list,(a,b)->(a.getId()-b.getId()));