【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
相关推荐
星沁城1 分钟前
122. 买卖股票的最佳时机 II
java·算法
有杨既安然38 分钟前
Python爬虫入门指南:从零开始抓取数据
开发语言·爬虫·python·信息可视化·数据分析·excel
中國移动丶移不动40 分钟前
Java字符编码与正则表达式深度解析
java·开发语言·正则表达式
从善若水40 分钟前
【Rust 学习笔记】Rust 基础数据类型介绍——指针、元组和布尔类型
笔记·学习·rust
Grovvy_Deng1 小时前
使用rust加速python的tgz解压
开发语言·python·rust
夜半被帅醒1 小时前
JAVA创建绘图板JAVA构建主窗口鼠标拖动来绘制线条
java·开发语言·计算机外设
TripleEyeAlien1 小时前
Swift Combine 学习(三):Subscription和 Subscriber
学习·ios·swift
所愿ღ1 小时前
Java线程
java·开发语言·笔记
荔枝点~1 小时前
使用GitLab+Jenkins搭建CICD执行环境
java·ci/cd·gitlab·jenkins·运维开发
盐盐8876901 小时前
【信息系统项目管理师】【综合知识】【备考知识点】【思维导图】第九章 项目范围管理
网络·经验分享·笔记·学习·运维开发