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语法合集

相关推荐
镜花照无眠25 分钟前
11个c语言编程练习题
c语言·开发语言
晨航33 分钟前
Flink新版Source接口源码解析
java·大数据·flink
ccsd112 小时前
jmeter并发测试
java·jmeter
2401_857600953 小时前
电商系统开发:Spring Boot框架实战
java·spring boot·后端
WAXXD3 小时前
Java读取WPS excel.xlsx嵌入图片
java·excel·wps
yava_free4 小时前
详解一下JVM诊断方法和其工具的使用
java·开发语言
南宫生4 小时前
力扣-Hot100-二叉树其二【算法学习day.33】
java·数据结构·学习·算法·leetcode·动态规划
小吕学编程5 小时前
开发中SQL积累
java·数据库·sql
KevinAha5 小时前
Tomcat 8.5 源码导读
java·tomcat
她说人狗殊途5 小时前
设计模式学习
java·学习·设计模式