Java集合相关学习——元素排序两大接口Comparable和Comparator的应用及区别

简介: Java集合相关学习——元素排序两大接口Comparable和Comparator的应用及区别

1.引出话题


Java 语言中,Comparable Comparator 都是用来进行元素排序的,但二者有着本质的区别。

2.Comparable


Comparable接口只有一个方法 compareTo,实现 Comparable 接口并重写 compareTo 方法就可以实现某个类的排序了,它支持 Collections.sort Arrays.sort 的排序。

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

具体实现代码如下:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.*;
import java.util.Map;
/**
 *
 */
class Man implements Comparable<Man> {
    private Integer id;
    private String name;
    private Integer age;
    public Man(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    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;
    }
    @Override
    public int compareTo(Man m) {
        return m.getAge() - this.getAge();
    }
    @Override
    public String toString() {
        return "Man{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class ComparableTest {
    public static void main(String[] args) {
        List<Man> list = new ArrayList<>();
        list.add(new Man(1, "张起灵", 18));
        list.add(new Man(2, "小哥", 22));
        list.add(new Man(3, "闷油瓶", 20));
        Collections.sort(list);
        list.forEach(System.out::println);
    }
}

3.Comparator


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

import java.util.*;
import java.util.Map;
/**
 *
 */
class Man2 implements Comparable<Man> {
    private String name;
    private Integer age;
    public Man2(String name, Integer age) {
        this.name = name;
        this.age = 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;
    }
    @Override
    public int compareTo(Man m) {
        return m.getAge() - this.getAge();
    }
    @Override
    public String toString() {
        return "Man2{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class ComparatorTest {
    private static Map<Integer, Man2> sortMap(Map<Integer, Man2> map) {
        //首先拿到 map 的键值对集合
        Set<Map.Entry<Integer, Man2>> entrySet = map.entrySet();
        //将 set 集合转为 List 集合,原因:为了使用工具类的排序方法
        List<Map.Entry<Integer, Man2>> list = new ArrayList<>(entrySet);
        //使用 Collections 集合工具类对 list 进行排序,排序规则使用匿名内部类来实现
        Collections.sort(list, new Comparator<Map.Entry<Integer, Man2>>() {
            @Override
            public int compare(Map.Entry<Integer, Man2> o1, Map.Entry<Integer, Man2> o2) {
                //自定义按照年龄的降序排序
                return o2.getValue().getAge() - o1.getValue().getAge();
            }
        });
        //创建一个新的有序的Map集合
        Map<Integer, Man2> linkedHashMap = new LinkedHashMap<>();
        //将 List 中的数据存储在 LinkedHashMap 中
        list.forEach(m -> {
            linkedHashMap.put(m.getKey(), m.getValue());
        });
        return linkedHashMap;
    }
    public static void main(String[] args) {
        Map<Integer, Man2> map = new HashMap<>();
        map.put(1, new Man2("张起灵", 18));
        map.put(2, new Man2("小哥", 22));
        map.put(3, new Man2("闷油瓶", 20));
        System.out.println("排序之前的map集合为:\n" + map);
        System.out.println("-------------------------------");
        Map<Integer, Man2> sortMap = sortMap(map);
        System.out.println("排序之后的map集合为:\n" + sortMap);
    }
}


4.对比二者


通过上面示例的实现代码我们可以看出,使用 Comparable 必须要修改原有的类,也就是你要排序那个类,就要在那个中实现 Comparable 接口并重写 compareTo 方法,所以 Comparable 更像是对内进行排序的接口。


Comparator 的使用则不相同,Comparator 无需修改原有类。也就是在最极端情况下,即使 Person 类是第三方提供的,我们依然可以通过创建新的自定义比较器 Comparator,来实现对第三方类 Person 的排序功能。也就是说通过 Comparator 接口可以实现和原有类的解耦,在不修改原有类的情况下实现排序功能,所以 Comparator 可以看作是对外提供排序的接口。


Comparable Comparator 都是用来实现元素排序的,它们二者的区别如下:

·       Comparable 比较的意思,而 Comparator 比较器的意思;

·       Comparable 是通过重写 compareTo 方法实现排序的,而 Comparator 是通过重写 compare 方法实现排序的;

·       Comparable 必须由自定义类内部实现排序方法,而 Comparator 是外部定义并实现排序的。

所以用一句话总结二者的区别:Comparable 可以看作是对内进行排序接口,而 Comparator 对外进行排序的接口。

相关文章
|
10天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
19天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
8天前
|
Java
那些与Java Set擦肩而过的重复元素,都经历了什么?
在Java的世界里,Set如同一位浪漫而坚定的恋人,只对独一无二的元素情有独钟。重复元素虽屡遭拒绝,但通过反思和成长,最终变得独特,赢得了Set的认可。示例代码展示了这一过程,揭示了成长与独特性的浪漫故事。
15 4
|
14天前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
|
12天前
|
SQL Java 数据库连接
从理论到实践:Hibernate与JPA在Java项目中的实际应用
本文介绍了Java持久层框架Hibernate和JPA的基本概念及其在具体项目中的应用。通过一个在线书店系统的实例,展示了如何使用@Entity注解定义实体类、通过Spring Data JPA定义仓库接口、在服务层调用方法进行数据库操作,以及使用JPQL编写自定义查询和管理事务。这些技术不仅简化了数据库操作,还显著提升了开发效率。
26 3
|
13天前
|
存储 算法 Java
为什么Java Set如此“挑剔”,连重复元素都容不下?
在Java的集合框架中,Set是一个独特的接口,它严格要求元素不重复,适用于需要唯一性约束的场景。Set通过内部数据结构(如哈希表或红黑树)和算法(如哈希值和equals()方法)实现这一特性,自动过滤重复元素,简化处理逻辑。示例代码展示了Set如何自动忽略重复元素。
22 1
|
14天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
20天前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
33 3
|
18天前
|
Java
Java代码解释++i和i++的五个主要区别
本文介绍了前缀递增(++i)和后缀递增(i++)的区别。两者在独立语句中无差异,但在赋值表达式中,i++ 返回原值,++i 返回新值;在复杂表达式中计算顺序不同;在循环中虽结果相同但使用方式有别。最后通过 `Counter` 类模拟了两者的内部实现原理。
Java代码解释++i和i++的五个主要区别
|
20天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
37 2