【Java 学习】Comparable接口 和 Comparator接口,掌控排序逻辑解析,深入 Comparable 和 Comparator 的优雅切换
💬 欢迎讨论:如对文章内容有疑问或见解,欢迎在评论区留言,我需要您的帮助!
👍 点赞、收藏与分享:如果这篇文章对您有所帮助,请不吝点赞、收藏或分享,谢谢您的支持!
🚀 传播技术之美:期待您将这篇文章推荐给更多对需要学习Java语言、低代码开发感兴趣的朋友,让我们共同学习、成长!
1. Comparable接口
1.1 为什么要使用Comparable接口
先看代码两组代码:
代码1:
import java.util.Arrays; public class Main { public static void main(String[] args) { // 创建一个数组 String[] strs = {"李华","小明", "小红"}; // 对数组进行排序 Arrays.sort(strs); // 打印 System.out.println(Arrays.toString(strs)); } }
上述代码可以打印出比较的后的顺序。
代码2:
import java.util.Arrays; class Student{ public String name; public int age; public Student(String name, int age){ this.name = name; this.age = age; } } public class Main { public static void main(String[] args) { Student[] stus = {new Student("小明",19), new Student("小红",20), new Student("小刚",18)}; // 对数组进行排序 Arrays.sort(stus); // 打印 System.out.println(Arrays.toString(stus)); } }
上述的代码发生报错:
点击之后会跳转到如下图的代码:
代码如下:
private static int countRunAndMakeAscending(Object[] a, int lo, int hi) { assert lo = 0) runHi++; } return runHi - lo; }
在源代码中,使用Array.sort()会把引用类型强制转化成Comparable
(Comparable) a[runHi++] 强制把 a引用变量转化成Comparable 类型,但是我们写的Student并没有实现接口Comparable ,所以发生报错
那么,String是不是实现了 Comparable接口呢?
看一看String的源代码:
那为什么都必须实现这个接口呢?
在讲解接口的时已经说过,接口是一个标准,大家都执行这个标准,设计出的程序才能通用。
如:
String 实现了Comparable接口,它可以用Arrays.sort()进行快速排序。
1.2 Comparable 接口的语法
特点:
(1)用于定义默认的排序规则。
(2)实现了 Comparable 的类对象可以直接通过 Collections.sort() 或 Arrays.sort() 方法进行排序。
(3)它属于对象本身的一部分,默认定义了对象之间的比较逻辑。
Comparable 接口中只有一个方法:
int compareTo(T o);
方法参数与返回值:
(1)参数:T o,表示要比较的对象。
(2)返回值:
-----------返回负数:当前对象小于传入对象。
-----------返回零:当前对象等于传入对象。
-----------返回正数:当前对象大于传入对象。
语法:
public class 类名 implements Comparable{ @Override public int compareTo(参数){ //... return 返回值; } }
示例:
// Comparable 什么类就需要填什么 public class Student implements Comparable { private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } // Comparable 接口只有此一个方法,实现 compareTo 方法 @Override public int compareTo(Student other) { return this.score - other.score; // 按照分数升序排序 // return other.score - this.score 按照分数降序排序 } }
1.3 Comparable 的使用
使用compareTo函数:
import java.util.Arrays; class Student implements Comparable{ public String name; public int age; public Student(String name, int age){ this.name = name; this.age = age; } @Override public int compareTo(Student s){ return this.age - s.age; } } public class Main { public static void main(String[] args) { Student s1 = new Student("小明",19); Student s2 = new Student("小红",20); System.out.println(s1.compareTo(s2)); } }
返回的是19 - 20 的值:
使用Ayyars.sort()按照年龄升序排序:
import java.util.Arrays; class Student implements Comparable{ public String name; public int age; public Student(String name, int age){ this.name = name; this.age = age; } @Override public int compareTo(Student s){ return this.age - s.age; // 升序排序 } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } } public class Main { public static void main(String[] args) { Student[] stus = {new Student("小明",19), new Student("小红",20), new Student("小刚",18)}; // 排序前 System.out.println("排序前:"+ Arrays.toString(stus)); // 对数组进行排序 Arrays.sort(stus); // 排序后 System.out.println("排序后"+Arrays.toString(stus)); } }
Arrays.sort()排序使用Student中的compareTo函数了吗?我们怎么知道呢?
在compareTo中添加一个加打印语句:
@Override public int compareTo(Student s){ System.out.println("comppareTo()"); return this.age - s.age; }
再次运行,结果:
很明显,使用Arrays.sort()时调用了compareTo函数。
2. Comparator 接口
2.1 为什么要有 Comparator 接口
一个有年龄排序方法的类:
class Student implements Comparable{ public String name; public int age; public int score; public Student(String name, int age, int score){ this.name = name; this.age = age; this.score = score; } @Override public int compareTo(Student s){ return this.age - s.age; // 升序排序 } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
Comarable 接口只能被重写一次,只能进行年龄比较,但是,我们要想进行排序的是分数score, 怎么办呢?
此时,Comarator接口可以解决这个问题。Comparator有很强的灵活性,可以设计比较任意的属性。
2.2 Comparator 接口的语法
特点:
(1)用于定义自定义的排序规则。
(2)它是一个独立的比较器,与对象本身的定义无关。
(3)当需要对同一类的对象应用多种排序规则时,Comparator 更加灵活。
(4)Comparator 的对象可以传递给 Collections.sort() 或 Arrays.sort() 方法。
Comparator 接口中有两个常用方法:
int compare(T o1, T o2); boolean equals(Object obj) //判断是否与另一个比较器相等(通常很少需要重写)
语法:
public class 类名 implements Comparator{ @Override public int compare(参数){ //... return 返回值; } }
2.3 Comparator 接口的使用
- 比较两个对象的成绩:
Studnet类:
public class Student { public String name; public int age; public int score; public Student(String name, int age, int score){ this.name = name; this.age = age; this.score = score; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
比较类:
import java.util.Comparator; // 注意,这里的类需要填进行比较的类 class ScoreSort implements Comparator{ // 重写比较函数 // 注意,这里的参数有两个 @Override public int compare(Student s1, Student s2){ return s1.score - s2.score; } }
两个对象的score进行比较:
public class Main { public static void main(String[] args) { // 创建两个对象 Student s1 = new Student("小明",19,80); Student s2 = new Student("小红",20,70); // 创建一个排序对象 ScoreSort ss = new ScoreSort(); // 打印出比较的结果 System.out.println(ss.compare(s1,s2)); } }
结果:
- 比较一个数组的成绩:
Arrays.sort()可以填入两个参数,只需要把Arrays.sort(array,object)中的object换成排序对象即可。
public class Main { public static void main(String[] args) { Student[] stus = {new Student("小明",19,80), new Student("小红",20,70), new Student("小刚",18,90)}; // 排序前 System.out.println("排序前:"+ Arrays.toString(stus)); // 创建排序的对象 ScoreSort scoreSort = new ScoreSort(); // 对数组进行排序 Arrays.sort(stus,scoreSort); //需要添加排序对象 // 排序后 System.out.println("排序后"+Arrays.toString(stus)); } }
结果:
3 Comparable 和 Comparator 的比较
Comparable 和 Comparator 的核心区别
特性 | Comparable | Comparator |
---|---|---|
用途 | 定义对象的默认排序规则 | 定义自定义的排序规则 |
位置 | 排序逻辑在对象内部实现 | 排序逻辑在外部定义 |
接口方法 | compareTo(T o) | compare(T o1, T o2) |
实现方式 | 对象类实现 Comparable 接口 | 通过实现 Comparator 接口创建比较器 |
灵活性 | 只能定义一种排序规则 | 可以定义多种排序规则 |
使用场景 | 对象有一个自然排序 | 对象需要多种排序规则或自定义排序 |
修改类代码的需求 | 必须修改类的代码以实现接口 | 不需要修改类的代码,可在外部定义排序逻辑 |
选择 Comparable 还是 Comparator?
使用场景 | 选择 |
---|---|
类的排序逻辑是固定的,且只有一种排序方式。 | Comparable |
类的排序逻辑可能有多种(如按年龄、按名字)。 | Comparator |
类的代码无法修改(如第三方库类)。 | Comparator |
需要更灵活的排序方式。 | Comparator |