【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
相关推荐
拓端研究室TRL2 小时前
R软件线性模型与lmer混合效应模型对生态学龙类智力测试数据层级结构应用
开发语言·r语言
于慨2 小时前
计算机考研C语言
c语言·开发语言·数据结构
GGGGGGGGGGGGGG.3 小时前
使用dockerfile创建镜像
java·开发语言
请为小H留灯3 小时前
Python中很常用的100个函数整理
开发语言·python
达斯维达的大眼睛3 小时前
QT小项目-简单的记事本
开发语言·qt
轩宇^_^3 小时前
C++ 类与对象的实际应用案例详解
开发语言·c++
oioihoii3 小时前
从零到多页复用:我的WPF MVVM国际化实践
开发语言·c#·wpf
云上艺旅3 小时前
K8S学习之基础二十:k8s的coredns
学习·容器·kubernetes
c7_ln4 小时前
编程视界:C++命名空间
开发语言·c++·笔记
兮动人4 小时前
SpringBoot加载配置文件的优先级
java·spring boot·后端·springboot加载配置