排序Comparable 和 Comparator的区别

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: 排序Comparable 和 Comparator的区别

[1] 区别


[1.1] 源码上的区别

  comparable接口实际上是出自java.lang包,它有一个compareTo(Object obj)方法用来排序;

  comparator接口实际上是出自java.util包,它有一个compare(Object obj1, Object obj2)方法用来排序;

[1.2] 字面上的区别

  Comparable翻译为中文是“比较”的意思,而Comparator是“比较器”的意思;

  Comparable是以 -able 结尾的,表示它自身具备着某种能力,而Comparator是以 -or 结尾,表示自身是比较的参与者,这是从字面含义先来理解二者的不同;

[1.3] 使用上的区别

  Comparable主要是被我们自己写的类来实现,然后由自定义类内部实现compareTo(Object obj)方法,帮助我们完成自定义类的自定义排序;当一个类实现Comparable之后,才可以去调用Collections.sortArrays.sort来排序

  Comparator是外部定义并实现排序的,实现compare(Object obj1, Object obj2)方法。

[2] Comparable


  在我们没有使用 Comparable 时,程序的执行是这样的:

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.ArrayList;
import java.util.List;
public class ComparableExample {
    public static void main(String[] args) {
        // 创建对象
        Person p1 = new Person(1, 18, "Java");
        Person p2 = new Person(2, 22, "MySQL");
        Person p3 = new Person(3, 6, "Redis");
        // 添加到集合
        List<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        // 打印集合信息
        list.forEach(p -> System.out.println(p.getName() +
                ":" + p.getAge()));
    }
}
// 以下 set/get/toString 都使用的是 lombok 提供的注解
@Getter 
@Setter
@ToString
class Person {
    private int id;
    private int age;
    private String name;
    public Person(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
}

  程序执行结果如下:

Java: 18
MySQL: 22
Redis: 6

 从上图可以看出,当自定义类 Person 没有实现 Comparable 时,List 集合是没有排序的,只能以元素的插入顺序作为输出的顺序。


 然而这个时候,老板有一个需求:需要根据 Person 对象的年龄 age 属性进行倒序,也就是根据 age 属性从大到小进行排序,这个时候就可以请出,我们本文的主角:Comparable 出场了。


 Comparable 的使用是在自定义对象的类中实现 Comparable 接口,并重写 compareTo 方法来实现自定义排序规则的,具体实现代码如下:

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ComparableExample {
    public static void main(String[] args) {
        // 创建对象
        Person p1 = new Person(1, 18, "Java");
        Person p2 = new Person(2, 22, "MySQL");
        Person p3 = new Person(3, 6, "Redis");
        // 添加对象到集合
        List<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        // 进行排序操作(根据 Person 类中 compareTo 中定义的排序规则)
        Collections.sort(list);
        // 输出集合中的顺序
        list.forEach(p -> System.out.println(p.getName() +
                ":" + p.getAge()));
    }
}
//  以下 set/get/toString 都使用的是 lombok 提供的注解实现的
@Getter
@Setter
@ToString
static class Person implements Comparable<Person> {
    private int id;
    private int age;
    private String name;
    public Person(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
    @Override
    public int compareTo(Person p) {
        return p.getAge() - this.getAge();
    }
}

  程序的执行结果如下:

MySQL: 22
Java: 18
Redis: 6

  compareTo 排序方法说明

  compareTo 方法接收的参数 p 是要对比的对象,排序规则是用当前对象和要对比的对象进行比较,然后返回一个 int 类型的值。正序从小到大的排序规则是:使用当前的对象值减去要对比对象的值;而倒序从大到小的排序规则刚好相反:是用对比对象的值减去当前对象的值。

  注意事项:如果自定义对象没有实现 Comparable 接口,那么它是不能使用 Collections.sort 方法进行排序的.

[3] Comparator


  Comparator 和 Comparable 的排序方法是不同的,Comparable 排序的方法是 compareTo,而 Comparator 排序的方法是 compare,具体实现代码如下:

import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparatorExample {
    public static void main(String[] args) {
        // 创建对象
        Person p1 = new Person(1, 18, "Java");
        Person p2 = new Person(2, 22, "MySQL");
        Person p3 = new Person(3, 6, "Redis");
        // 添加对象到集合
        List<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        // 进行排序操作(根据 PersonComparator 中定义的排序规则)
        Collections.sort(list, new PersonComparator());
        // 输出集合中的顺序
        list.forEach(p -> System.out.println(p.getName() +
                ":" + p.getAge()));
    }
}
/**
  * 用于 Person 类的比较器
  */
class PersonComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p2.getAge() - p1.getAge();
    }
}
@Getter
@Setter
class Person {
    private int id;
    private int age;
    private String name;
    public Person(int id, int age, String name) {
        this.id = id;
        this.age = age;
    }
}

  程序的执行结果如下:

MySQL: 22
Java: 18
Redis: 6

  扩展:Comparator 匿名类

  Comparator 除了可以通过创建自定义比较器外,还可以通过匿名类的方式,更快速、便捷的完成自定义比较器的功能,具体的代码实现如下:

import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class ComparatorExample {
    public static void main(String[] args) {
        // 构建并添加数据
        List<Person> list = new ArrayList<>();
        list.add(new Person(1, 18, "Java"));
        list.add(new Person(2, 20, "MySQL"));
        list.add(new Person(3, 6, "Redis"));
        // 使用 Comparator 匿名类的方式进行排序
        list.sort(new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {
                return p2.getAge() - p1.getAge();
            }
        });
        // 打印集合数据
        list.forEach(p -> System.out.println(p.getName() +
                ":" + p.getAge()));
    }
}
@Getter
@Setter
static class Person {
    private int id;
    private int age;
    private String name;
    public Person(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
}
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
5月前
|
Java
Comparable和Comparator两种比较器详解
Comparable和Comparator两种比较器详解
20 0
|
9月前
Comparable与Comparator对象比较
Comparable与Comparator对象比较
30 0
Comparable和Comparator有什么区别?你知道他们和Arrays.sort的关系吗?
Comparable和Comparator有什么区别?你知道他们和Arrays.sort的关系吗?
74 0
|
搜索推荐 算法 安全
浅谈Comparable和Comparator
首先我们考虑一个场景:有一个整形数组, 我们希望通过调用一个工具类的排序方法就能对该数组进行排序. 请看下面的代码:
Comparable与Comparator有什么区别?
Comparable与Comparator有什么区别?
177 0
|
Java
Java对象的比较和排序(Comparator和Comparable)
Java对象的比较和排序(Comparator和Comparable)
123 0
Java对象的比较和排序(Comparator和Comparable)
关于Comparator和Comparable的理解
关于Comparator和Comparable的理解
89 0
|
Java
说说Comparator比较器那些用法
关于java的排序,在java8之后有了函数式接口之后,就产生了很多种Comparator比较器的写法。细数一下那些常用的比较器。
1251 1
说说Comparator比较器那些用法