引用数据类型是不能直接使用比较运算符来比较大小的

及到对象之间的比较问题:使用自然排序(Comparable)、定制排序(Comparator)

Comparable 自然排序

Comparable 接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的 自然排序

使用步骤:

  1. 具体的类A实现Comparable接口
  2. 重写Comparable接口中的 compareTo(Object obj) 方法,在此方法中指明比较类A的对象的大小的标准
  3. 创建类A的多个实例,进行大小的比较或排序。

举例

// 具体的类A实现Comparable接口
public class Student implements Comparable{
  private int id;
  private String name;
  private int age;
  private int score;
  public Student(){}

  public Student(int id, String name,int score,int age) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.score = score;
  }
	// 省略 get/set方法。。。
  
  
	// 重写Comparable接口中的compareTo(Object obj)方法
  @Override
  public int compareTo(Object o) {
    if(o instanceof Student){
      Student student = (Student) o;
      // 按学号比大小
      return this.id - student.id;
    }
    return 0;
  }
}

// 测试
@Test
public void TestCompareTo{
  Student[] arr = new Student[5];
  arr[0] = new Student(3,"张三",90,23);
  arr[1] = new Student(1,"熊大",100,22);
  arr[2] = new Student(5,"王五",75,25);
  arr[3] = new Student(4,"李四",85,24);
  arr[4] = new Student(2,"熊二",85,18);
  // 单个比较,学号
  System.out.println(arr[0].compareTo(arr[1]));
  // 进行排序,学号
  Arrays.sort(arr);
  System.out.println(Arrays.toString(arr));
}

Comparator 定制排序

当元素的类型没有实现 java.lang.Comparable 接口而又不方便修改代码

例如:一些第三方的类,你只有.class 文件,没有源文件

此情况采用 定制排序 Comparator

实现步骤

  1. 创建一个实现了 Comparator 接口的实现类A
  2. 实现类A要求重写 Comparator 接口中的抽象方法 compare(Object o1,Object o2),在此方法中指明要比较大小的对象的大小关系(比如,String类、Product类)
  3. 创建此实现类A的对象,并将此对象传入到相关方法的参数位置即可(比如:Arrays.sort(…,类A的实例))

举例

// 省略 与上面相同的Student类。。。

// 创建一个实现了 Comparator 接口的实现类A
public class StudentComparator implements Comparator {
  // 重写 Comparator 接口中的抽象方法
  @Override
  public int compare(Object o1, Object o2) {
    if(o1 instanceof Student && o2 instanceof Student){
      Student s1 = (Student) o1;
      Student s2 = (Student) o2;
      int res = s1.getScore() - s2.getScore();
      // 按成绩比较
      return res == 0 ? s1.getId() - s2.getId() : res;
    }
    throw new RuntimeException("类型不匹配");
  }
}

// 测试
@Test
public void TestCompare{
  Student[] arr = new Student[5];
  arr[0] = new Student(3,"张三",90,23);
  arr[1] = new Student(1,"熊大",100,22);
  arr[2] = new Student(5,"王五",75,25);
  arr[3] = new Student(4,"李四",85,24);
  arr[4] = new Student(2,"熊二",85,18);
  // 创建此实现类A的对象
  StudentComparator sc = new StudentComparator();
  // 并将此对象传入到相关方法的参数位置,进行排序,学号
  Arrays.sort(arr,sc);
  System.out.println(Arrays.toString(arr));
  // 分割线=====
  // 实现方法二 ,匿名类
  // 使用匿名类
  Arrays.sort(arr,new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
      // 按年龄排序
      return o1.getAge() - o2.getAge();
    }
  });
}

对比两种方式

  • 角度一:
    自然排序:单一的,唯一的
    定制排序:灵活的,多样的
  • 角度二:
    自然排序:一劳永逸的
    定制排序:临时的
  • 角度三:细节
    自然排序:对应的接口是Comparable,对应的抽象方法 compareTo(Object obj)
    定制排序:对应的接口是Comparator,对应的抽象方法 compare(Object obj1,Object obj2)

参考资料

尚硅谷Java基础