【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
相关推荐
dkmilk几秒前
Tomcat发布websocket
java·websocket·tomcat
工一木子22 分钟前
【Java项目脚手架系列】第七篇:Spring Boot + Redis项目脚手架
java·spring boot·redis
哞哞不熬夜34 分钟前
JavaEE--初识网络
java·网络·java-ee
等等5431 小时前
Java EE初阶——wait 和 notify
java·开发语言
低代码布道师1 小时前
第五部分:第一节 - Node.js 简介与环境:让 JavaScript 走进厨房
开发语言·javascript·node.js
API小爬虫1 小时前
淘宝按图搜索商品(拍立淘)Java 爬虫实战指南
java·爬虫·图搜索算法
盛夏绽放1 小时前
Python字符串常用方法详解
开发语言·python·c#
lyrhhhhhhhh1 小时前
Spring 框架 JDBC 模板技术详解
java·数据库·spring
黄暄1 小时前
初识计算机网络。计算机网络基本概念,分类,性能指标
笔记·学习·计算机网络·考研
梅子酱~2 小时前
Vue 学习随笔系列二十三 -- el-date-picker 组件
前端·vue.js·学习