深度解析Java中的Comparable接口和Comparator接口

 大家好,我是小鱼儿

新的一天,大家一起加油!

目录

引子

Comparable接口

Comparator接口 


引子

我们之前的文章的文章提到了Arrays是一个数组工具类,用Arrays.sort能够对各种类型的数组进行排序,那下面的数组能不能用Arrays.sort排序呢?

class Student {  // 自定义的学生类
    String name;
    int age;

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

    @Override  // 对父类Object的父类方法进行重写,以便直接打印出当前对象的值
    public String toString() { 
        // 这是IDEA的自动生成的toString重写,你也可以按照自己的喜好自由的选择打印的形式
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class test4 {
    public static void main(String[] args) {
        Student[] students = new Student[] { // 我们定义了一个数组,数组中每个元素都是一个学生对象
              new Student("zhangsan", 13),
              new Student("lisi", 23),
              new Student("able", 17),
        };
        Arrays.sort(students); // 用类Arrays.sort对students数组进行排序
        System.out.println(Arrays.toString(students));
        // 注意这里的toString是Arrays自己的toString方法,和Object类中的toString方法不是同一个方法,
        // 只是碰巧同名,参数都不一样,Arrays的有参数,Object没参数
        // 我们前几篇文章专门对Arrays以及toString方法的重写做了说明,这里不再赘述
    }
}

但你运行的时候,你会发现程序报错了😮

对了,我记得sort只能对给定长度的数组排序,否则会发出空指针异常,但这里就是给定长度的数组啊!为啥还是错呢?

程序抛出了异常😮,你说不对呀!我的Arrays不是对任意的数组都可以进行操作吗?之前我们就用Arrays.toString成功打印了数组元素都是对象的一个数组呀!

但是朋友,你告诉Arrays拿什么排了吗?是按姓名 还是按年龄呢? 

🍑所以我们要告诉编译器那什么来排序,而这就要用到我们的Comparable接口

Comparable接口

📝通过参考手册我们可以看到

 我们的程序就可以写成这样

//Comparable接口在java.lang这个包下面,而java.lang这个包由java解释器自动引入,而不用import语句引入
class Student implements Comparable<Student>{  // 实现Comparable接口,注意Comparable后要加上要比较的对象的类型<Student>
    String name;
    int age;

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

    @Override  // 对父类Object的父类方法进行重写,以便直接打印出当前对象的值
    public String toString() {
        return "[" + this.name + ":" + this.age + "]";
    }

    @Override // 实现Comparable接口中的中的compareTo方法
    public int compareTo(Student o) {
        if (this.age > o.age) return 1;  // this.代表对当前对象的引用,o.代表对参数对的引用
        else if (this.age < o.age) return -1;
        else return 0;
    }
    //如果当前对象应排在参数对象之前, 返回小于 0 的数字;
    //比如上面我们如果this.age>o.age,那么返回1,就this.age在o.age的后面,即按年龄升序排列
    //如果当前对象应排在参数对象之后, 返回大于 0 的数字;
    //如果当前对象和参数对象不分先后, 返回 0;
}
public class test4 {
    public static void main(String[] args) {
        Student[] students = new Student[] { // 我们定义了一个数组,数组中每个元素都是一个学生对象
              new Student("zhangsan", 13),
              new Student("lisi", 23),
              new Student("able", 17),
        };
        Arrays.sort(students); // 用类Arrays.sort对students数组进行排序
        System.out.println(Arrays.toString(students));
        // 注意这里的toString是Arrays自己的toString方法,和Object类中的toString方法不是同一个方法,
        // 只是碰巧同名,参数都不一样,Arrays的有参数,Object没参数
        // 我们前几篇文章专门对Arrays以及toString方法的重写做了说明,这里不再赘述
    }
}

😁看一下输出结果

📝咱们再回过头来看看为为啥必须要实现接口中的 compareTo 方法,

 

​​​​​​​上图中的这个(Comparable)a[runHi++]数组就是我们Arrays.sort传过去的学生对象数组🤔,下图中的this指的是谁🤔?就要看谁此时调用了compareTo方法😎

上图中compareTo(a[lo])点号前面的的学生对象a[runHi++]就是此时的this😮。下图中的o对象就是上图中的compareTo(a[lo]中的a[lo]学生对象

不知道你理解了吗😂?如果没理解,我们不妨再举一个栗子 

🌰总结一下

 📝我们知道在Arrays.sort(students); 中是传了一个学生对象数组,如上图所示在调用Arrays对对象数组排序的时候,其实就调用了我们的Comparable接口中的compareTo方法对数组的每个元素进行了排序😁

📝其实在Java中对于引用数据类型的比较或者排序,一般都要用到使用Comparable接口中的compareTo() 方法

🍑那如何按年龄排序呢?一样的道理(只是发生了一些小小的变化)

//Comparable接口在java.lang这个包下面,而java.lang这个包由java解释器自动引入,而不用import语句引入
class Student implements Comparable<Student>{  // 实现Comparable接口,注意Comparable后要加上要比较的对象的类型<Student>
    String name;
    int age;

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

    @Override  // 对父类Object的父类方法进行重写,以便直接打印出当前对象的值
    public String toString() {
        return "[" + this.name + ":" + this.age + "]";
    }

    @Override // 实现Comparable接口中的中的compareTo方法
    public int compareTo(Student o) {
        // 为啥在compareTo里还要用compareTo,因为name是个String类型也是个引用类型,也需要用compareTo比较, 不过这里用到的compareTo方法是String类里重写的
        if (this.name.compareTo(o.name) > 0) return 1;  // this.代表对当前对象的引用,o.代表对参数对的引用
        else if (this.name.compareTo(o.name) < 0) return -1;
        else return 0;
    }
    //如果当前对象应排在参数对象之前, 返回小于 0 的数字;
    //如果当前对象应排在参数对象之后, 返回大于 0 的数字;
    //如果当前对象和参数对象不分先后, 返回 0;
}
public class test4 {
    public static void main(String[] args) {
        Student[] students = new Student[] { // 我们定义了一个数组,数组中每个元素都是一个学生对象
              new Student("zhangsan", 13),
              new Student("lisi", 23),
              new Student("able", 17),
        };
        Arrays.sort(students); // 用类Arrays.sort对students数组进行排序
        System.out.println(Arrays.toString(students));
        // 我们前几篇文章专门对Arrays以及toString方法的重写做了说明,这里不再赘述
    }
}

bi 

📝但这样会有一个问题,那就是一但写好了排序的方法,那就一下子就写死了😮。你在compareTo方法里实现的是按年龄比较,那你接下来就只能按年龄来比较🤔。如果想按姓名来比较,那只能够在重写compareTo方法。 

🍑那有什么办法能够解决这个问题呢?

有!那就是我们接下来要讲的比较器:Comparator接口 


Comparator接口

🌰老规矩我们先来了解一下Comparator这个接口

所以就像Comparable 接口一样,我们只要实现了Comparator接口,并重写Comparator里的compare方法就可以实现对学生对象数组的排序

🌰比如我们上面的年龄比较就可以写成这样

class Student { 
    String name;
    int age;

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

    @Override  // 对父类Object的父类方法进行重写,以便直接打印出当前对象的值
    public String toString() {
        return "[" + this.name + ":" + this.age + "]";
    }
}
class AgeComparator implements Comparator<Student> { // 年龄比较器
    @Override  // 实现Comparator接口中的compare方法
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    // 反正返回的也是数字,当o1.age>o2.age时返回大于零的数,即o1对象排在o2对象的后面,升序排列,我们之前用Comparable接口时也可以这样简写
    }
    //如果当前对象应排在参数对象之前, 返回小于 0 的数字;
    //如果当前对象应排在参数对象之后, 返回大于 0 的数字;
    //如果当前对象和参数对象不分先后, 返回 0;
}
public class test4 {
    public static void main(String[] args) {
        Student[] students = new Student[]{ // 我们定义了一个数组,数组中每个元素都是一个学生对象
                new Student("zhangsan", 13),
                new Student("lisi", 23),
                new Student("able", 17),

        };
        AgeComparator ageComparator = new AgeComparator(); // 对年龄比较器进行实例化
        Arrays.sort(students, ageComparator); 
        // 用类Arrays.sort对students数组进行排序,这里传了两个参数(学生对象和所对应的年龄比较器)
        System.out.println(Arrays.toString(students));
        // 我们前几篇文章专门对Arrays以及toString方法的重写做了说明,这里不再赘述
    }
}

📝Arrays.sort此时是一个传两个参数的方法: 

 🌰那姓名比较比较自然就出来了

class Student {
    String name;
    int age;

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

    @Override  // 对父类Object的父类方法进行重写,以便直接打印出当前对象的值
    public String toString() {
        return "[" + this.name + ":" + this.age + "]";
    }
}
class NameComparator implements Comparator<Student> { // 姓名比较器
    @Override  // 实现Comparator接口中的compare方法
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name); 
// 因为name是String类型,也是一个引用类型,也要用到compareTo方法,此时的compareTo方法是String类里重写的方法
    }
    //如果当前对象应排在参数对象之前, 返回小于 0 的数字;
    //如果当前对象应排在参数对象之后, 返回大于 0 的数字;
    //如果当前对象和参数对象不分先后, 返回 0;
}
public class test4 {
    public static void main(String[] args) {
        Student[] students = new Student[]{ // 我们定义了一个数组,数组中每个元素都是一个学生对象
                new Student("zhangsan", 13),
                new Student("lisi", 23),
                new Student("able", 17),

        };
        NameComparator nameComparator = new NameComparator();
        Arrays.sort(students, nameComparator); // 用类Arrays.sort对students数组进行排序
        System.out.println(Arrays.toString(students));
        // 我们前几篇文章专门对Arrays以及toString方法的重写做了说明,这里不再赘述
    }
}

总结一下就是:

📝Comparable接口和Comparator接口都是Java中用来比较和排序引用类型数据的接口,要实现比较,就需要实现他们所各种对应的compareTo方法或者compare方法。

🌰不同的是:Comparator使用起来更加灵活,所以我更倾向于使用比较器:Comparator

但注意,sort只能对给定长度的数组排序,否则会发出空指针异常

好了,今天我们就聊到这里,咱们下篇博客见🥰 

  • 79
    点赞
  • 229
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 41
    评论
评论 41
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是小鱼儿哈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值