自学内容网 自学内容网

【Java 学习】Comparable接口 和 Comparator接口,掌控排序逻辑解析,深入 Comparable 和 Comparator 的优雅切换

💬 欢迎讨论:如对文章内容有疑问或见解,欢迎在评论区留言,我需要您的帮助!

👍 点赞、收藏与分享:如果这篇文章对您有所帮助,请不吝点赞、收藏或分享,谢谢您的支持!

🚀 传播技术之美:期待您将这篇文章推荐给更多对需要学习Java语言、低代码开发感兴趣的朋友,让我们共同学习、成长!

1. Comparable接口

1.1 为什么要使用Comparable接口

先看代码两组代码:

代码1:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {

        // 创建一个数组
        String[] strs = {"李华","小明", "小红"};

        // 对数组进行排序
        Arrays.sort(strs);

        // 打印
        System.out.println(Arrays.toString(strs));

    }
}

上述代码可以打印出比较的后的顺序。

代码2:

import java.util.Arrays;

class Student{
    public String name;
    public int age;

    public Student(String name, int age){
        this.name = name;
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {

        Student[] stus = {new Student("小明",19), new Student("小红",20), new Student("小刚",18)};

        // 对数组进行排序
        Arrays.sort(stus);

        // 打印
        System.out.println(Arrays.toString(stus));

    }
}

上述的代码发生报错:
在这里插入图片描述
点击之后会跳转到如下图的代码:
在这里插入图片描述
代码如下:

private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {
        assert lo < hi;
        int runHi = lo + 1;
        if (runHi == hi)
            return 1;

        // Find end of run, and reverse range if descending
        
        // 解释:
//               a 是引用变量,此时是Student类型的引用变量
//    Comparable 强制把 a引用变量转化成comparable 类型,
// 但是我们写的Student并没有实现接口Comparable ,所以发生报错
        if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending
            while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)
                runHi++;
            reverseRange(a, lo, runHi);
        } else {                              // Ascending
            while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 0)
                runHi++;
        }

        return runHi - lo;
    }

在源代码中,使用Array.sort()会把引用类型强制转化成Comparable

(Comparable) a[runHi++] 强制把 a引用变量转化成Comparable 类型,但是我们写的Student并没有实现接口Comparable ,所以发生报错

那么,String是不是实现了 Comparable接口呢?

看一看String的源代码:
在这里插入图片描述
那为什么都必须实现这个接口呢?

在讲解接口的时已经说过,接口是一个标准,大家都执行这个标准,设计出的程序才能通用。

如:
String 实现了Comparable接口,它可以用Arrays.sort()进行快速排序。

1.2 Comparable 接口的语法

特点
(1)用于定义默认的排序规则。
(2)实现了 Comparable 的类对象可以直接通过 Collections.sort() 或 Arrays.sort() 方法进行排序。
(3)它属于对象本身的一部分,默认定义了对象之间的比较逻辑。

Comparable 接口中只有一个方法:

int compareTo(T o);

方法参数与返回值:
(1)参数:T o,表示要比较的对象。
(2)返回值:
-----------返回负数:当前对象小于传入对象。
-----------返回零:当前对象等于传入对象。
-----------返回正数:当前对象大于传入对象。

语法:

public class 类名 implements Comparable<类名>{
    
    @Override
    public int compareTo(参数){
        //...
        
        return 返回值;
    }
}

示例

//                               Comparable<> 什么类就需要填什么
public class Student implements Comparable<Student> {
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    // Comparable 接口只有此一个方法,实现 compareTo 方法
    @Override
    public int compareTo(Student other) {
        return this.score - other.score; // 按照分数升序排序
        // return other.score - this.score 按照分数降序排序
    }

}

1.3 Comparable 的使用

使用compareTo函数:

import java.util.Arrays;

class Student implements Comparable<Student>{
    public String name;
    public int age;

    public Student(String name, int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Student s){
        return this.age - s.age;
    }

}

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("小明",19);
        Student s2 = new Student("小红",20);
        
        System.out.println(s1.compareTo(s2));
    }
}

返回的是19 - 20 的值:
在这里插入图片描述

使用Ayyars.sort()按照年龄升序排序:

import java.util.Arrays;

class Student implements Comparable<Student>{
    public String name;
    public int age;

    public Student(String name, int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Student s){
        return this.age - s.age; // 升序排序
    }


    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class Main {
    public static void main(String[] args) {

        Student[] stus = {new Student("小明",19), new Student("小红",20), new Student("小刚",18)};

        // 排序前
        System.out.println("排序前:"+ Arrays.toString(stus));

        // 对数组进行排序
        Arrays.sort(stus);

        // 排序后
        System.out.println("排序后"+Arrays.toString(stus));

    }
}

在这里插入图片描述
Arrays.sort()排序使用Student中的compareTo函数了吗?我们怎么知道呢?

compareTo中添加一个加打印语句:

@Override
    public int compareTo(Student s){
        System.out.println("comppareTo()");
        return this.age - s.age;
    }

再次运行,结果:
在这里插入图片描述
很明显,使用Arrays.sort()时调用了compareTo函数。

2. Comparator 接口

2.1 为什么要有 Comparator 接口

一个有年龄排序方法的类:

class Student implements Comparable<Student>{
    public String name;
    public int age;
    public int score;

    public Student(String name, int age, int score){
        this.name = name;
        this.age = age;
        this.score = score;
    }

    @Override
    public int compareTo(Student s){
        return this.age - s.age; // 升序排序
    }


    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Comarable 接口只能被重写一次,只能进行年龄比较,但是,我们要想进行排序的是分数score, 怎么办呢?

此时,Comarator接口可以解决这个问题。Comparator有很强的灵活性,可以设计比较任意的属性。

2.2 Comparator 接口的语法

特点:
(1)用于定义自定义的排序规则。
(2)它是一个独立的比较器,与对象本身的定义无关。
(3)当需要对同一类的对象应用多种排序规则时,Comparator 更加灵活。
(4)Comparator 的对象可以传递给 Collections.sort()Arrays.sort() 方法。

Comparator 接口中有两个常用方法:

int compare(T o1, T o2);

boolean equals(Object obj) //判断是否与另一个比较器相等(通常很少需要重写)

语法:

public class 类名 implements Comparator<需要比较类的类>{
    
    @Override
    public int compare(参数){
        //...
        
        return 返回值;
    }
}

2.3 Comparator 接口的使用

  1. 比较两个对象的成绩

Studnet类

public class Student {
    public String name;
    public int age;
    public int score;

    public Student(String name, int age, int score){
        this.name = name;
        this.age = age;
        this.score = score;
    }


    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

比较类

import java.util.Comparator;
                        // 注意,这里的类需要填进行比较的类
class ScoreSort implements Comparator<Student>{
// 重写比较函数
// 注意,这里的参数有两个
    @Override
    public int compare(Student s1, Student s2){
        return s1.score - s2.score;
    }
}

两个对象的score进行比较:

public class Main {
    public static void main(String[] args) {
        // 创建两个对象
        Student s1 = new Student("小明",19,80);
        Student s2 = new Student("小红",20,70);

        // 创建一个排序对象
        ScoreSort ss = new ScoreSort();

// 打印出比较的结果
        System.out.println(ss.compare(s1,s2));

    }
}

结果:
在这里插入图片描述

  1. 比较一个数组的成绩

Arrays.sort()可以填入两个参数,只需要把Arrays.sort(array,object)中的object换成排序对象即可。

public class Main {
    public static void main(String[] args) {

        Student[] stus = {new Student("小明",19,80),
                new Student("小红",20,70), new Student("小刚",18,90)};

        // 排序前
        System.out.println("排序前:"+ Arrays.toString(stus));

        // 创建排序的对象
        ScoreSort scoreSort = new ScoreSort();

        // 对数组进行排序
        Arrays.sort(stus,scoreSort);  //需要添加排序对象

        // 排序后
        System.out.println("排序后"+Arrays.toString(stus));

    }
}

结果:
在这里插入图片描述

3 Comparable 和 Comparator 的比较

ComparableComparator 的核心区别

特性ComparableComparator
用途定义对象的默认排序规则定义自定义的排序规则
位置排序逻辑在对象内部实现排序逻辑在外部定义
接口方法compareTo(T o)compare(T o1, T o2)
实现方式对象类实现 Comparable 接口通过实现 Comparator 接口创建比较器
灵活性只能定义一种排序规则可以定义多种排序规则
使用场景对象有一个自然排序对象需要多种排序规则或自定义排序
修改类代码的需求必须修改类的代码以实现接口不需要修改类的代码,可在外部定义排序逻辑

选择 Comparable 还是 Comparator

使用场景选择
类的排序逻辑是固定的,且只有一种排序方式。Comparable
类的排序逻辑可能有多种(如按年龄、按名字)。Comparator
类的代码无法修改(如第三方库类)。Comparator
需要更灵活的排序方式。Comparator

原文地址:https://blog.csdn.net/2302_79527141/article/details/144769455

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!