自然排序与比较器排序
自然排序,即按字典顺序排序(升序排序),是默认的排序方式。对于 Arrays.sort() 与 Collections.sort() 方法,如果我们不指定比较器,使用的就是自然排序,也就是按升序排序。
如果想让元素降序排列或以我们指定的方式进行排序,就需要自定义比较器了,这可以通过 Comparable 或 Comparator 接口来实现。
Comparable接口
java.lang.Comparable 接口定义的 compareTo() 方法用于提供对实现它的对象进行整体排序。Comparable 接口只有一个方法 compareTo(Object obj)。
compareTo(Object obj)方法的工作原理是返回一个 int 值:
- 如果this < obj,返回负值
- 如果this == obj,返回零
- 如果this > obj ,返回正值
在 compareTo() 方法中,很多人会写成类似下面这样的形式
public int compareTo(Node n) {
//下面这句代码是有问题的,例如当i1为正数,i2为负数时,可能会发生溢出。
return i1 - i2;
}
为了避免发生类似的错误,应该采用三元操作符。
用户在重写 compareTo() 方法的比较逻辑时,建议最好使自然排序与 equals 方法返回的结果一致。
实际上,所有实现 Comparable 接口的 系统类都具有与 equals 一致的自然排序。java.math.BigDecimal 是个例外,它的自然排序将值相等但精确度不同的 BigDecimal 对象(如 4.0 和 4.00)视为相等。
类型 | 排序方式 |
Byte Short Integer Long Float Double Boolean BigInteger BigDecimal | 按数字大小排序 |
Character | 按 Unicode 值的数字大小排序 |
String | 按字符串中字符 Unicode 值排序 |
如果 List 实现了该接口的话 , 我们就可以调用 Collections.sort()方法(实际上调用的是Arrays.sort()方法)给他们排序。
JDK 1.8 在 List 接口中增加了 sort() 方法,调用关系链如下:
![](https://i-blog.csdnimg.cn/blog_migrate/3c083c5809c84ac783a4643230898478.png)
示例如下:
List<String> list = new ArrayList<>();
list.add("2");
list.add("3");
list.add("1");
list.sort(Comparator.naturalOrder());
System.out.println(list);
输出结果:
[1, 2, 3]
Comparator接口
实现 Comparator 接口的类必须实现实现 compare(Object o1, Object o2) 方法,返回负值、零或正值。
Comparator 接口的作用主要有下面几点:
- 如果类的设计师没有考虑到 Compare 的问题而没有实现 Comparable 接口,可以通过 Comparator 来实现比较算法进行排序
- 为了使用不同的排序标准,比如按自定义的属性进行排序。
- Comparator 可以看做是外部比较器,Comparable 是内部比较器。
下面是使用 Comparable 与 Comparator 接口的示例:
public class Student implements Comparable<Student> {
private int id;
private String name;
private int score;
private Student(int id, String name, int score) {
this.id = id;
this.name = name;
this.score = score;
}
@Override
public int compareTo(Student s) {
return Integer.compare(id, s.id);
}
@Override
public String toString() {
return "ID:" + id + " Name:" + name + " Score:" + score;
}
public static void main(String[] args) {
Student[] stu = new Student[5];
stu[0] = new Student(2, "Luna", 100);
stu[1] = new Student(0, "Kate", 96);
stu[2] = new Student(1, "Harry", 95);
stu[3] = new Student(4, "Alice", 94);
stu[4] = new Student(3, "Iris", 92);
Arrays.sort(stu);
System.out.println("使用Comparable接口排序(按id升序):");
System.out.println(Arrays.toString(stu));
Arrays.sort(stu, (o1, o2) -> Integer.compare(o2.score, o1.score));
System.out.println("使用Comparator接口排序(按成绩降序):");
System.out.println(Arrays.toString(stu));
}
}
输出结果:
使用Comparable接口排序(按id升序):
[ID:0 Name:Kate Score:96, ID:1 Name:Harry Score:95, ID:2 Name:Luna Score:100, ID:3 Name:Iris Score:92, ID:4 Name:Alice Score:94]
使用Comparator接口排序(按成绩降序):
[ID:2 Name:Luna Score:100, ID:0 Name:Kate Score:96, ID:1 Name:Harry Score:95, ID:4 Name:Alice Score:94, ID:3 Name:Iris Score:92]
内置的比较器是按照ID升序排序,如果想要按照成绩排序,Comparator 就可以实现这个功能。在上面的例子中,Comparator 采用了 Java 8 中的 Lamda 表达式实现。