Comparator 与 Comparable 有什么区别,分别适用于哪些情况?

一、认识Comparator 与 Comparable

ComparatorComparable是在Java中用于对象比较和排序的接口。

1.1 Comparable

java 复制代码
java.lang.Comparable

Comparable接口是在被比较的对象自身中实现的,它定义了对象的自然排序顺序。

一个实现了Comparable接口的类可以通过实现compareTo()方法来定义对象的比较逻辑。

compareTo()方法返回一个负整数、零或正整数,分别表示当前对象小于、等于或大于传入的对象。

Comparable接口在对象的内部提供了默认的比较规则。

1.2 Comparator

java 复制代码
java.util.Comparator

Comparator接口是一个独立的比较器,它实现了比较逻辑但不需要修改被比较的对象本身。

Comparator接口定义了compare()方法,允许在对象之间进行比较。

Comparator对象可以用于对不同类的对象进行排序,或者对同一类的对象采用不同的排序规则。

Comparator提供了一种外部比较机制,可以在不改变对象定义或创建Comparator实例的情况下,对对象进行排序。

二、Comparator 与 Comparable 有什么区别

看了上面的内容都知道这两个都不是一个玩意儿,但是具体有哪些区别呢,我做了一个表格总结如下:

特点 Comparable接口 Comparator接口
实现位置 被比较的对象类中 独立的比较器类中
默认排序 提供对象的自然排序,默认排序规则 没有默认排序规则,需要显式创建Comparator对象
修改对象 改变对象自身的比较逻辑 不修改被比较的对象
多重排序 只能定义一种排序方式 可以定义多个不同的排序规则

可以说一个自已完成比较,一个外部程序实现比较差别而已。 用Comparator 策略模式(strategy design pattern),就不改变对象自身,而用一个策略对象(strategy object)来改变它行为。

比如:你想对整数采用绝对值大小来排序,Integer 不符合要求,你不需要去修改Integer 类(实际上你也不能这么做)去改变它排序行为,只要使用一个实现了 Comparator 接口口对象来实现控制它排序就行了。

三、Comparator 和Comparable 分别适用于哪些情况?

graph LR A(分别适用于哪些情况) B(Comparator) C(Comparable) D(外部比较) E(多重排序) F(定制排序) I(动态排序) CD(自然排序) CE(修改对象) CF(单一排序) A ---> B A ---> C B ---> D B ---> E B ---> F B ---> I C ---> CD C ---> CE C ---> CF style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px style E fill:#98FB98,stroke:#98FB98,stroke-width:2px style F fill:#B2FFFF,stroke:#B2FFFF,stroke-width:2px style I fill:#EEDD82,stroke:#EEDD82,stroke-width:2px style CD fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px style CE fill:#98FB98,stroke:#98FB98,stroke-width:2px style CF fill:#B2FFFF,stroke:#B2FFFF,stroke-width:2px

3.1 Comparator 接口适用情况

  • 外部比较 :当你需要对已有的类进行比较,但无法修改这些类的源代码时,可以使用Comparator接口来定义比较规则。

  • 多重排序 :如果你需要根据不同的比较规则对对象进行排序,可以创建多个Comparator对象来满足不同的排序需求。

  • 定制排序 :当类本身没有实现Comparable接口,或者你想要覆盖默认的比较规则时,可以使用Comparator接口来定义对象的比较逻辑。

  • 动态排序Comparator接口允许你在运行时动态选择不同的比较规则,而不需要修改被比较的对象本身。

3.2 Comparable 接口适用情况

  • 自然排序 :当你想要定义对象的默认排序规则时,可以实现Comparable接口并在compareTo()方法中定义对象的比较逻辑。

  • 修改对象 :如果你有权修改对象的类,并且希望改变对象自身的比较逻辑,可以实现Comparable接口来定义对象的比较方式。

  • 单一排序Comparable接口只能定义一种排序规则,适用于不需要多个不同的比较规则的情况。

四、Comparator 和Comparable 使用案例

前面说了那么多,可能大家还是不清晰,下面使用两种案例来演示一下他们的区别:

4.1 使用 Comparator 案例

假设有一个名为Person的类,你可以创建一个PersonComparator实现Comparator接口,然后在compare()方法中定义比较逻辑,如按照年龄升序排序:

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
  • 对自定义类进行排序
java 复制代码
// 实现接口离开来实现比较
class PersonComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }
}

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Demo {

    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        // 添加Person对象到列表
        Collections.sort(people, new PersonComparator());
    }

}
  • 使用匿名内部类进行排序(建议使用,更加简洁)
java 复制代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Demo {

    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        // 添加Person对象到列表
        Collections.sort(people, new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {
                return p2.getName().compareTo(p1.getName());
            }
        });
    }

}

4.2 使用 Comparable 案例

假设有一个名为Student的类,你可以让它实现Comparable接口,并在compareTo()方法中定义按照学号升序排序的逻辑

  • 排序实现
java 复制代码
public class Student implements Comparable<Student> {

    /**
     * 姓名
     */
    private Integer name;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 学号
     */
    private Integer studentId;

    @Override
    public int compareTo(Student other) {
        return this.studentId - other.studentId;
    }

}
  • 使用方法
java 复制代码
public class Test {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        // 添加Student对象到列表
        Collections.sort(students);
    }
}

五、总结

在使用Comparable接口时,对象自身就具备了默认的比较规则,可以直接使用Collections.sort()Arrays.sort()等方法进行排序。而使用Comparator接口时,你可以创建多个不同的比较器对象,并通过传递给排序方法来指定使用哪个比较器进行排序。

ComparatorComparable都提供了灵活的比较和排序机制,实际开发中可以根据具体的需求选择适合的接口来实现对象的比较和排序。

希望本文能给你带来帮助,如有错误或建议,欢迎指正和提出。

相关推荐
2401_8576226615 分钟前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
2402_8575893619 分钟前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
吾爱星辰43 分钟前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
哎呦没1 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
_.Switch2 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
编程、小哥哥2 小时前
netty之Netty与SpringBoot整合
java·spring boot·spring
IT学长编程3 小时前
计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·玩具租赁系统
莹雨潇潇3 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
杨哥带你写代码3 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
AskHarries4 小时前
读《show your work》的一点感悟
后端