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 对外进行排序的接口。

相关文章
|
6天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
14 2
|
6天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
10天前
|
存储 Java 开发者
Java中的集合框架深入解析
【10月更文挑战第32天】本文旨在为读者揭开Java集合框架的神秘面纱,通过深入浅出的方式介绍其内部结构与运作机制。我们将从集合框架的设计哲学出发,探讨其如何影响我们的编程实践,并配以代码示例,展示如何在真实场景中应用这些知识。无论你是Java新手还是资深开发者,这篇文章都将为你提供新的视角和实用技巧。
11 0
|
3月前
|
Java
"Java排序大揭秘:Comparable与Comparator,究竟有何神秘区别?掌握它们,告别排序难题!"
【8月更文挑战第19天】Java提供Comparable与Comparator两种排序机制。Comparable位于`java.lang`包,定义了`compareTo()`方法以实现类的自然排序;Comparator位于`java.util`包,通过`compare()`方法提供外部定制排序。实现Comparable固定了排序策略,适用于类自带排序逻辑;使用Comparator则可在不改动类的前提下灵活定义多种排序规则,适合多样化的排序需求。选择合适机制可优化排序效率并增强代码灵活性。
25 0
|
5月前
|
Java
Java中Comparable接口和Comparator接口的区别(如果想知道Java中Comparable接口和Comparator接口的区别,那么只看这一篇就足够了!)
Java中Comparable接口和Comparator接口的区别(如果想知道Java中Comparable接口和Comparator接口的区别,那么只看这一篇就足够了!)
|
算法 Java 开发者
21. 你能说说Java中Comparable和Comparator的区别吗
21. 你能说说Java中Comparable和Comparator的区别吗
93 0
java中Comparable和Comparator的区别
java中Comparable和Comparator的区别
|
8天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
4天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
22 9