前言

包装类Collections的排序方法可以运用到各种集合框架,非常方便

接口分析

Comparable接口

  • Comparable接口在 java.lang.Comparable 包下
  • Comparable接口的实现方法:public int compareTo(T t);
  • Comparable接口是在集合的(类的)内部实现的排序方式,调用的实质 t1.compareTo(t2);
  • 在排序对象本身支持相互比较所需要的接口(如Integer、String、Double、Float等)时,可以直接调用 Collections.sort() 方法的Comparable接口(参考程序示例)
  • 当数值或ASCII码值从小到大的默认顺序或者排序的根据对象不满足程序需求时,可以重写compareTo方法(参考程序示例)

Comparator接口

  • Comparator接口在 java.util.Comparator 包下
  • Comparator接口的实现方法:public int compare(T t1, T t2);
  • Comparator接口是在集合的(类的)外部实现的排序方式,需要用到一个比较容器,*调用的实质是 compare(t1 , t2);*(参考程序示例)
  • 在排序对象本身不支持相互比较所需要的接口,例如对整数采用绝对值大小排序,显然对象本身的Integer自然排序是不能实现的,同时如果Integer类也不容许你在它的内部重写compareTo()去改变它的排序行为,所以就可以用到Comparator接口(参考程序示例)

compareTo和compare方法

  • Comparable接口的实现方法:public int compareTo(T t),调用的实质 t1.compareTo(t2);

    在方法内部返回一个运算结果,例如返回:t1.x - t2.x,则按从小到大的顺序排序

    若返回:t2.x - t1.x,则按从大到小的顺序排序

  • Comparator接口的实现方法:public int compare(T t1, T t2),调用的实质是 compare(t1 , t2);

    在方法内部返回一个运算结果,例如返回:t1.x - t2.x,则按从小到大的顺序排序

    若返回:t2.x - t1.x,则按从大到小的顺序排序

  • compareTo默认的调用可以实现字符串的比较,比较方法:先比较第一个字符,不同则返回ASCII码的差值,若第一个字符相同,则比较第二个字符,若前面字符相同则比较长度。

例如:

String a = 'abc';
String b = 'cde';
String c = 'abcde';
int d = a.compareTo(b);
int e = a.compareTo(c);

返回d = -2,由a的ASCII码值减去b的ASCII码值得来。e = -2,因为前字符相同,a.length() - c.length() = -2


相关之处

  • 对于一个对象的排序,既可以用Comparable接口实现,也能用Comparator接口实现,只是两种排序的实现方式不同,
  • 在某些情况的排序下,可以用Comparator接口,在接口的compare方法中再次调用compareTo方法进行比较。例如如下情况:

输入学生的学号、姓名、班级、成绩,分别根据这四个数据进行排序。

  1. 对学号的排序,可以调用Comparable接口重写comparaTo方法按学号从小到大排序

  2. 对姓名的排序,可以实现一个比较容器,在容器中重写compare方法,在compare方法中调用compareTo方法实现对字符串的比较,然后返回对字符串的比较结果。

class NameUPComparator implements java.util.Comparator {
public int compare(Object o1, Object o2) {
Student s1 = (Student)o1;// 转化成当前类型的对象
Student s2 = (Student)o2;
return s1.getName().compareTo(s2.getName());
}
}

在调用sort方法时,则要通过:

Collections.sort(studentList,new NameUPComparator());

程序示例

调用默认的Comparable接口

import java.util.ArrayList;
import java.util.Collections;

public class CompObj {

public String toString() {
return "[x = " + x + "]";
}

public static void main(String[] args) {
ArrayList<Integer> al = new ArrayList<Integer>();// 单一Integer数据的ArrayList,有本身支持比较的接口Integer
al.add(3);
al.add(1);
al.add(2);
System.out.println("Before sort!");
for (int i = 0; i < al.size(); i++) {
System.out.println(al.get(i));
}
Collections.sort(al); // 调用Collections的sort方法-静态方法
System.out.println("After sort!");
for (int i = 0; i < al.size(); i++) {
System.out.println(al.get(i));
}
}

运行结果如下所示:

image.png

调用重写compareTo方法的Comparable接口

根据x值排序

import java.util.ArrayList;
import java.util.Collections;

public class CompObj implements java.lang.Comparable { // 定义要排序的类

int x;
int y;

public CompObj(int n1, int n2) {
x = n1;
y = n2;
}

public String toString() {
return "[x = " + x + ", y = " + y + "]";
}

public int compareTo(Object o) {
CompObj co = (CompObj) o;
if (this.x != co.x) {
return this.x - co.x;
} else {
return this.y - co.y;
}
}

public static void main(String[] args) {
ArrayList<CompObj> al = new ArrayList<CompObj>();
al.add(new CompObj(3, 1));
al.add(new CompObj(1, 3));
al.add(new CompObj(2, 2));
al.add(new CompObj(2, 1));
System.out.println("Before sort!");
for (int i = 0; i < al.size(); i++) {
System.out.println(al.get(i));
}
Collections.sort(al); // 调用Collections的sort方法-静态方法
System.out.println("After sort!");
for (int i = 0; i < al.size(); i++) {
System.out.println(al.get(i));
}
}

}

输出结果:

注意事项

  • compareTo()方法的形参为Object类的对象,在比较之前要进行类型转换成为CompObj类的对象

  • 在重写的compareTo方法中,若俩对象的x值相同,则比较y值

  • 若改为

    if (this.x != co.x) {
    return co.x - this.x;
    } else {
    return co.y - this.y;
    }

    则按照从大到小的顺序排序


调用重写compareTo方法的Comparator接口

根据y值排序

import java.util.ArrayList;
import java.util.Collections;

class ObjComparator implements java.util.Comparator {
public int compare(Object o1, Object o2) {
CompObj co1 = (CompObj) o1; // 转化成当前类型的对象
CompObj co2 = (CompObj) o2;
if (co1.y != co2.y) {
return co1.y - co2.y;// 先根据y值排序
} else {
return co1.x - co2.x;
}
}
}

public class CompObj { // 无需实现Comparable接口
int x;
int y;

public CompObj(int n1, int n2) {
x = n1;
y = n2;
}

public String toString() {
return "[x = " + x + ", y = " + y + "]";
}

public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add(new CompObj(3, 2));
al.add(new CompObj(1, 3));
al.add(new CompObj(1, 2));
System.out.println("Before sort!");
for (int i = 0; i < al.size(); i++) {
System.out.println(al.get(i));
}
Collections.sort(al, new ObjComparator());
System.out.println("After sort!");
for (int i = 0; i < al.size(); i++) {
System.out.println(al.get(i));
}
}
}
image.png

调用重写compareTo方法的Comparator接口实现绝对值排序

根据x的绝对值排序

import java.util.ArrayList;
import java.util.Collections;

class AbsComparator implements java.util.Comparator {
public int compare(Object o1, Object o2) {
CompObj co1 = (CompObj) o1;// 转化成当前类型的对象
CompObj co2 = (CompObj) o2;
int v1 = Math.abs(co1.x);// 把对象co1的x成员转化成绝对值
int v2 = Math.abs(co2.x);
return v1 - v2;
}
}

public class CompObj { // 无需实现Comparable接口
int x;
int y;

public CompObj(int n1, int n2) {
x = n1;
y = n2;
}

public String toString() {
return "[x = " + x + ", y = " + y + "]";
}

public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add(new CompObj(3, 2));
al.add(new CompObj(-2, 3));
al.add(new CompObj(1, 2));
System.out.println("Before sort!");
for (int i = 0; i < al.size(); i++) {
System.out.println(al.get(i));
}
Collections.sort(al, new AbsComparator());
System.out.println("After sort!");
for (int i = 0; i < al.size(); i++) {
System.out.println(al.get(i));
}
}
}
image.png