Collections
是集合的工具类,它提供了很多便于我们操作集合的方法, 其中就有用于集合排序的 sort
方法。
实际上,在使用Collection的sort排序的集合元素都必须是Comparable
接口的实现类,该接口表示子类是可以比较的。因为实现接口必须重写抽象方法 - int compareTo(T t)。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class Test1 {
public static void main(String[] args) {
List<Integer> list0 = new ArrayList<>();
Random random = new Random();
for(int i = 0; i<10;i++){
list0.add(random.nextInt(100));
}
System.out.println(list0);//[46, 7, 91, 48, 52, 25, 64, 3, 28, 60]
/*
* 对集合进行自然排序,从小到大
*/
Collections.sort(list0);
System.out.println(list0);//[2, 19, 44, 46, 61, 67, 68, 89, 91, 94]
List<String> list1 = new ArrayList<>();
list1.add("Alive");
list1.add("Rose");
list1.add("Jack");
list1.add("Noname");
System.out.println(list1); //[Alive, Rose, Jack, Noname]
Collections.sort(list1);
/*
*对集合进行自然排序,显而易见是按照首字母顺序排序
*/
System.out.println(list1);//[Alive, Jack, Noname, Rose]
}
}
那么你有没有发现在该类中我并没有实现Comparable接口,那么为什么
我对 list0 和 list1集合排序时没有报错呢?
原因:查询源码可知 Integer、String 类都实现了Comparable接口,所以在对list0和list1集合排序时没有报错。
那么问题来了对象这个大小之分是如何判断呢?
实际上,在使用Collection的sort排序的集合元素都必须是Comparable接口的实现类,该接口表示子类是可以比较的。
因为实现接口必须重写抽象方法。
- int compareTo(T t);
该方法用于使当前对象与给定对象进行比较。
返回值为一个int值,该值表示大小关系,它不关注具体的取值是多少,而关注的是取值范围。
当返回值>0时:当前对象比参数对象大
当返回值<0时:当前对象比参数对象小
当返回值=0时:当前对象等于参数对象
cell类
public class Cell implements Comparable<Cell>{
//哪个类实现Comparable接口泛型就写哪个类
private int x;
private int y;
public Cell(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "Cell [x=" + x + ", y=" + y + "]";
}
@Override
public int compareTo(Cell o) {
//自定义排序逻辑
// TODO Auto-generated method stub
return this.x-o.x; //以传入的Cell的横坐标由小到大进行排序
}
}
@Test
public void testComparable(){
/*
* Cell实现了Comparable接口,compareTo方法逻辑为按照x值大小进行排序
*/
List<Cell> cells = new ArrayList<Cell>();
cells.add(new Cell(2,3));
cells.add(new Cell(5,1));
cells.add(new Cell(3,2));
//[Cell [x=2, y=3], Cell [x=5, y=1], Cell [x=3, y=2]]
System.out.println(cells);
Collections.sort(cells);
//[Cell [x=2, y=3], Cell [x=3, y=2], Cell [x=5, y=1]]
System.out.println(cells);
}
我们想使用sort方法排序集合,但是该方法要求我们的集合元素必须实现Comparable接口并且定义比较规则,这种我们想使用某个功能,而它要求我们修改程序的现象称为“侵入性”。修改的代码越多,侵入性比较强,越不利于程序的扩展。
所以不建议使用这个构造方法。
重载的sort方法要求传入一个额外的比较器
该方法不再要求集合元素必须实现Comparable接口,并且也不再使用集合元素自身的比较规则排序了,而是根据给定的这个额外的比较器的比较规则对集合元素进行排序。
实际开发中也推荐使用这种方式排序集合元素,若集合元素是自定义的,创建比较器时也推荐使用匿名内部类的形式。
方法一:自定义一个比较器然后传入Collections.sort(List,Comparator)中。
测试代码:
自定义的比较器:
import java.util.Comparator;
public class MyComparator implements Comparator<Cell>{
@Override
public int compare(Cell o1, Cell o2) {
//根据传入的cell的y坐标由小到大进行排序
return o1.getY()-o2.getY();
}
}
测试类:
@Test
public void testComparator() {
List<Cell> cells = new ArrayList<>();
cells.add(new Cell(2,3));
cells.add(new Cell(5,1));
cells.add(new Cell(3,2));
//[Cell [x=2, y=3], Cell [x=5, y=1], Cell [x=3, y=2]]
System.out.println(cells);
MyComparator com = new MyComparator();
Collections.sort(cells,com);
//根据自定义排序后的结果:[Cell [x=5, y=1], Cell [x=3, y=2], Cell [x=2, y=3]]
System.out.println(cells);
}
方法二:采用匿名内部的形式(推荐做法)
@Test
public void testComparator() {
List<Cell> cells = new ArrayList<>();
cells.add(new Cell(2,3));
cells.add(new Cell(5,1));
cells.add(new Cell(3,2));
System.out.println(cells);//[Cell [x=2, y=3], Cell [x=5, y=1], Cell [x=3, y=2]]
Collections.sort(cells,new Comparator<Cell>(){
//此处创建了一个匿名内部类
@Override
public int compare(Cell o1,Cell o2){
return o1.getY() - o2.getY();
}
});
System.out.println(cells);//[Cell [x=5, y=1], Cell [x=3, y=2], Cell [x=2, y=3]]
}