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

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

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

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

1. Comparable接口

1.1 为什么要使用Comparable接口

先看代码两组代码:

代码1:

java 复制代码
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:

java 复制代码
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));

    }
}

上述的代码发生报错:

点击之后会跳转到如下图的代码:

代码如下:

java 复制代码
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 接口中只有一个方法:

java 复制代码
int compareTo(T o);

方法参数与返回值:

(1)参数:T o,表示要比较的对象。

(2)返回值:

-----------返回负数:当前对象小于传入对象。

-----------返回零:当前对象等于传入对象。

-----------返回正数:当前对象大于传入对象。

语法:

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

示例

java 复制代码
//                               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函数:

java 复制代码
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()按照年龄升序排序:

java 复制代码
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中添加一个加打印语句:

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

再次运行,结果:

很明显,使用Arrays.sort()时调用了compareTo函数。

2. Comparator 接口

2.1 为什么要有 Comparator 接口

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

java 复制代码
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 接口中有两个常用方法:

java 复制代码
int compare(T o1, T o2);

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

语法:

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

2.3 Comparator 接口的使用

  1. 比较两个对象的成绩:

Studnet类

java 复制代码
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 +
                '}';
    }
}

比较类

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

两个对象的score进行比较:

java 复制代码
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换成排序对象即可。

java 复制代码
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 的核心区别

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

选择 Comparable 还是 Comparator

使用场景 选择
类的排序逻辑是固定的,且只有一种排序方式。 Comparable
类的排序逻辑可能有多种(如按年龄、按名字)。 Comparator
类的代码无法修改(如第三方库类)。 Comparator
需要更灵活的排序方式。 Comparator
相关推荐
wb0430720118 分钟前
性能优化实战:基于方法执行监控与AI调用链分析
java·人工智能·spring boot·语言模型·性能优化
LXS_35725 分钟前
Day 05 C++ 入门 之 指针
开发语言·c++·笔记·学习方法·改行学it
MicroTech20251 小时前
微算法科技(MLGO)研发突破性低复杂度CFG算法,成功缓解边缘分裂学习中的掉队者问题
科技·学习·算法
天若有情6731 小时前
Java Swing 实战:从零打造经典黄金矿工游戏
java·后端·游戏·黄金矿工·swin
etsuyou2 小时前
js前端this指向规则
开发语言·前端·javascript
lichong9512 小时前
Android studio 修改包名
android·java·前端·ide·android studio·大前端·大前端++
shizhenshide2 小时前
为什么有时候 reCAPTCHA 通过率偏低,常见原因有哪些
开发语言·php·验证码·captcha·recaptcha·ezcaptcha
lichong9512 小时前
Git 检出到HEAD 再修改提交commit 会消失解决方案
java·前端·git·python·github·大前端·大前端++
@yanyu6662 小时前
Tomcat安装与HTML响应实战
java·tomcat·html
mit6.8242 小时前
[Agent可视化] 配置系统 | 实现AI模型切换 | 热重载机制 | fsnotify库(go)
开发语言·人工智能·golang