Java(十二)——Comparable接口与Comparator接口

文章目录

Comparable与Comparator接口

我们可能会遇到这样的问题:怎么对一个对象数组进行排序? 比如对一个狗类对象数组进行排序,而想到这,我们又会有一个问题:怎么比较两个对象?如果我想自定义标准,怎么办?

与基本类型的比较并排序不同,对象数组没有一个统一的标准来进行比较来排序,此时就可以基于Comparable接口实现或者基于比较器实现(Comparator接口)

  1. 自然排序:基于Comparable接口
  2. 定制排序:基于Comparator接口

本文均以自定义的Person类为例:

java 复制代码
public class Person {
    private String name;
    private int age;


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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

}

Comparable接口

使用了Comparable接口,意味着此类可排序,使用方法是:在想要实现比较的类中实现Comparable接口并重写compareTo()方法

我们先观察一下Comparable接口的源码:

我们发现,Comparable接口中只有一个CompareTo方法

观察完毕后,我们看如下实现代码:

java 复制代码
//Person.java
//实现Comparable接口
public class Person implements Comparable<Person> {
    private String name;
    private int age;


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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    //重写compareTo方法,这里按照name(字符串)比较
    @Override
    public int compareTo(Person o) {
        if(this.name.compareTo(o.name) > 0) {
            return 1;
        }else if(this.name.compareTo(o.name) < 0) {
            return -1;
        }else {
            return 0;
        }
    }
}


//Test.java
import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        Person[] people = new Person[]{new Person("zhangsan", 23), new Person("lisi", 15),
                                       new Person("wangwu", 42)};

        //实现了Comparable接口后,可以通过Arrays类中的排序方法给对象数组排序了
        Arrays.sort(people);
        for(Person p : people) {
            System.out.println(p);
        }
    }
}

打印结果如下:

  • Comparable接口后面的<>是泛型知识,传入要比较的类即可

  • 实现Comparable接口必须重写CompareTo方法,方法要求返回int类型的值,一般内部实现的逻辑:

    调用方法的对象 > 作为参数的对象,返回正数;调用方法的对象 < 作为参数的对象,返回负数;调用方法的对象 == 作为参数的对象,返回0

  • 一个类实现了Comparable接口,那么就可以调用Arrays类中的sort方法对存放此类对象的数组进行排序

  • 一个实现了Comparable接口的类只能重写一个compareTo方法,这也意味着标准被固定


Comparator接口

前面提到,基于Comparable接口实现比较的标准固定,且不便在原代码修改,这种情况下,我们可以通过Comparator接口(比较器)实现,方法是:定义一个或多个比较器类,实现Comparator接口,并重写Compare方法

我们先观察一下Comparator接口的一部分源码:

这部分源码显示,Comparator接口中包含compareequals方法,实现了Comparator接口的类可以不重写equals方法,但是一定要重写compare方法

观察完毕后,我们看如下实现代码:

java 复制代码
//Person.java
public class Person {
    private String name;
    private int age;


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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

}

//AgeComparator.java
//以年龄比较的比较器
import java.util.Comparator;

public class AgeComparator implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        return o1.getAge() - o2.getAge();
    }
}

//NameComparator.java
//以名字比较的比较器
import java.util.Comparator;

public class NameComparator implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        return o1.getName().compareTo(o2.getName());
    }
}

//Test.java
import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        Person[] people = new Person[]{new Person("zhangsan", 23), new Person("lisi", 15),
                                       new Person("wangwu", 42)};
        
        //使用时,必须实例化比较器对象
        AgeComparator ageComparator = new AgeComparator();
        NameComparator nameComparator = new NameComparator();

        //正常使用
        System.out.println(ageComparator.compare(new Person("张三", 16), new Person("李四", 10)));

        //与Arrays类中的sort方法配合使用
        Arrays.sort(people, ageComparator);
        for(Person p : people) {
            System.out.println(p);
        }
    }
}

打印结果如下:

  • 要比较的对象的类不需要实现Comparator接口,比较器需要实现Comparator接口,并在<>内给出要比较的类,并重写compare方法
  • 重写的compare方法有两个参数,分别是要比较的两个对象,重写的compare方法要求:返回值的正负以及零,表示不同的比较结果。例如,左参数对象大于右参数对象,返回正值;左参数对象小于右参数对象,返回负值;左右参数对象相等,返回0
  • 使用时,必须实例化比较器类对象。可以选择直接调用其中的compare方法比较单一对象,也可以配合Arrays类中的sort方法对对象数组进行排序,此时sort方法需要两个参数:1. 对象数组 2. 比较器对象
  • 比较器可以创建若干个,意味着我们可以定义多个标准,相对灵活一些

区别:

  1. Comparable 相当于 "内部比较器",Comparator相当于 "外部比较器"
  2. 对于基于Comparable的比较,需要手动实现接口,侵入性比较强,但一旦实现,每次调用该类都有顺序,属于内部顺序
  3. 对于基于Comparator的比较,需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性强
    侵入性:让用户代码产生对框架的依赖,这些代码不能直接脱离框架使用,不利于代码的复用

关于对象的比较,数据结构部分会经常用到


我们的SE部分的补充知识到此结束了,小裤马上会发一篇SE语法合集

相关推荐
渣哥1 天前
原来 Java 里线程安全集合有这么多种
java
间彧1 天前
Spring Boot集成Spring Security完整指南
java
间彧1 天前
Spring Secutiy基本原理及工作流程
java
Java水解1 天前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆1 天前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学1 天前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole1 天前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端
华仔啊1 天前
基于 RuoYi-Vue 轻松实现单用户登录功能,亲测有效
java·vue.js·后端
程序员鱼皮1 天前
刚刚 Java 25 炸裂发布!让 Java 再次伟大
java·javascript·计算机·程序员·编程·开发·代码