IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 源码详解 Comparable 和 Comparator 接口, compareTo 方法和 compare 方法的区别和使用 -> 正文阅读

[Java知识库]源码详解 Comparable 和 Comparator 接口, compareTo 方法和 compare 方法的区别和使用

前言

对集合中的元素排序,我们可以使用 Collections 工具类如:

	List<Integer> list1 = new ArrayList<>();
	list1.add(2);
	list1.add(1);
	list1.add(5);
	System.out.println(list1);
	Collections.sort(list1);
	System.out.println(list1);
	// 输出
	[2, 1, 5]
	[1, 2, 5]

为什么是升序排序?
怎么改为降序呢?
如果想要对一个学生的属性进行排序?如:

class Student {
    public String name;
    public int age;
    public double score;

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
}
public class TestDemo {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student("张三", 12, 70));
        list.add(new Student("李四", 18, 81));
        list.add(new Student("王五", 21, 93));
        
        System.out.println(list);
        // 显然这里是不行的
        Collections.sort(list);
        System.out.println(list);
    }
}

显然这里是不行的,谁知道这是按学生的哪个属性排序,那么怎么去自定义排序的方式呢?


1.这里为什么是升序排序?

先说结论:Integer 包装类 实现了Comparable 接口,重写了 compareTo 方法,而 compareTo 方法的返回值影响排序是升序还是降序

1.1 我们来看看 JDK1.8 的源码

Collections.sort 源码:
在这里插入图片描述
我们这里的 List 保存的是 Integer 类型,源码这里可知 Integer 一定实现了Comparable 接口
我们看看 Integer包装类 确实继承了Comparable 接口
在这里插入图片描述

1.2 Comparable 接口

再看看 Comparable 接口,接口中只有一个 compareTo 的抽象方法, 返回一个 int 类型的值在这里插入图片描述
Integer 包装类中重写 compareTo 方法,compareTo 方法中调用了 compare 方法在这里插入图片描述
compare 方法返回的 0 或者 -1 或者 1 取决于传入两数的大小,在 x < y返回 -1,x > y 返回1,x = y 返回 0;
在这里插入图片描述

1.3 Comparable 接口中的 compareTo 方法和排序有什么关系?

sort 传入null
在这里插入图片描述
这里圈起来的都为 null
在这里插入图片描述
在这里插入图片描述
点进这里
在这里插入图片描述
继续
在这里插入图片描述
终于破案了,我们的 list 一路传递到这里,在这里调用了 刚才的 compareTo 方法,这里就是排序的部分代码,compareTo 方法的返回值影响排序是升序还是降序如果前一个数大于后一个数,返回1,交换顺序,升序排序。
在这里插入图片描述

2.怎么改为降序呢?

由上边的分析我们可知只需修改 compareTo 的比较方式就行,但是这里的 compareTo 方法是 Integer 包装类中重写的,我们没办法修改。那让我们再看看另外一个 sort 的重载方法,发现还有第二个参数
在这里插入图片描述

2.1 Comparator 接口

Comparator 接口中有一个 compare的抽象方法,也是返回一个 int 类型
在这里插入图片描述

2.2 Comparator 接口中的 compare 方法和排序有什么关系?

这次传入的第二个参数不为 null,进入这里
在这里插入图片描述
在这里插入图片描述
最后同 compareTo 一样,在最后 compare 比较返回值影响排序的结果
在这里插入图片描述

2.3 实现 Comparator 接口,改为降序排序

不会写没关系,直接复制刚才 Integer 里的代码,修改 (x < y) ? -1 : ((x == y) ? 0 : 1); 修改为
(x > y) ? -1 : ((x == y) ? 0 : 1),相当于调换了 1 和 -1 的返回

class MyCompare implements Comparator<Integer> {
    @Override
    public int compare(Integer x, Integer y) {
        return (x > y) ? -1 : ((x == y) ? 0 : 1);
    }
}
public class TestDemo {
    public static void main(String[] args) {
        List<Integer> list1 = new ArrayList<>();
        list1.add(2);
        list1.add(1);
        list1.add(5);
        System.out.println(list1);
        MyCompare myCompare = new MyCompare();
        Collections.sort(list1, myCompare);
        System.out.println(list1);
	}
}
// 输出:
[2, 1, 5]
[5, 2, 1]

我们还可以将 compare 方法修改为这样,这是相同的意思,而且更简便。

class MyCompare implements Comparator<Integer> {
    @Override
    public int compare(Integer x, Integer y) {
        return y - x;
    }
}

2.4 使用匿名内部类和 lambda 表达式

以下几种方式都可以实现降序排序,为方便记忆,o1 作为第一个参数, o2 作为第二个参数,o2 - o1 降序(2 ,1),o1 - o2 升序(1,2)

	Collections.sort(list1, new Comparator<Integer>() {
	    @Override
	    public int compare(Integer o1, Integer o2) {
	        return o2 - o1;
	    }
	});
	// lambda 表达式
	Collections.sort(list1, (Integer o1, Integer o2) -> {return o2 - o1; });
	// 简写
	Collections.sort(list1, (o2, o1) -> o2 - o1);
	// Collections.sort 也是调用了list.sort,所以也可以直接这样写
	list1.sort((o2, o1) -> o2 - o1);

3.对一个学生的属性进行排序

3.1 Student 类实现 Comparable 接口

因为 Student 是我们写的类,那么就可以学这 Integer 包装类 去实现 Comparable 接口,先看看刚才 Integer 是怎么写的
在这里插入图片描述
this.value 作为第一个参数,compareTo 传入的参数作为第二个参数
在这里插入图片描述
我们也可以理解为

    public int compareTo(Integer o) {
        return this.value- o.value;
    }

自己实现

class Student implements Comparable<Student>{
    public String name;
    public int age;
    public double score;

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        return this.age - o.age;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student("张三", 12, 70));
        list.add(new Student("李四", 21, 81));
        list.add(new Student("王五", 18, 93));
        System.out.println(list);
        Collections.sort(list);
        System.out.println(list);
    }
}
// 运行结果,按年龄升序排序
[Student{name='张三', age=12, score=70.0}, Student{name='李四', age=21, score=81.0}, Student{name='王五', age=18, score=93.0}]
[Student{name='张三', age=12, score=70.0}, Student{name='王五', age=18, score=93.0}, Student{name='李四', age=21, score=81.0}]

这里我们看出来要修改比较的东西时,就可能要重新修改重写的方法,而正常情况下Student 是封装好的,所以这个局限性就比较大,这才有了 Comparator 接口,也称之为比较器
而刚才在创建类时 就实现 Comparable 接口 定义的排序方式称自然排序或内部排序

3.2 基于 Comparator 接口,自定义比较器

public class TestDemo {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student("张三", 12, 70));
        list.add(new Student("李四", 21, 81));
**加粗样式**        list.add(new Student("王五", 18, 93));
        System.out.println(list);
        // 自然排序
        Collections.sort(list);
        System.out.println(list);
        // 自定义比较器
        Collections.sort(list, (o1, o2) -> (int) (o2.score - o1.score));
        System.out.println(list);
    }
}

4.总结

Java 集合框架 Collections 工具类中的 sort 方法可以对集合中元素排序,前提是对象是可比较的,我们可以通过创建对象时实现Comparable 接口,或者在调用 sort 方法时将自己实现的 Comparator(比较器)接口作为参数传入。

4.1 Comparable 接口 和 Comparator 接口比较

  1. Comparable 接口在创建类时要手动实现并重写 compareTo 方法,一旦实现,每次用该类都有指定的顺序,属于内部顺序。如果要更换比较的方式,则要修改 compareTo 方法,侵入性强。

  2. Comparator(比较器)接口实现后作为参数传入Collections.sort。每次使用都要确定比较器,比较方式在实现比较器的时候重写 compare 方法确定,侵入性较弱。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-09 20:33:44  更:2022-02-09 20:36:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 12:59:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码