💬 欢迎讨论:如对文章内容有疑问或见解,欢迎在评论区留言,我需要您的帮助!
👍 点赞、收藏与分享:如果这篇文章对您有所帮助,请不吝点赞、收藏或分享,谢谢您的支持!
🚀 传播技术之美:期待您将这篇文章推荐给更多对需要学习Java语言、低代码开发感兴趣的朋友,让我们共同学习、成长!
1. Comparable接口
1.1 为什么要使用Comparable接口
先看代码两组代码:
代码1:
java
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:
java
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));
}
}
上述的代码发生报错:
点击之后会跳转到如下图的代码:
代码如下:
java
private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {
assert lo < hi;
int runHi = lo + 1;
if (runHi == hi)
return 1;
// Find end of run, and reverse range if descending
// 解释:
// a 是引用变量,此时是Student类型的引用变量
// Comparable 强制把 a引用变量转化成comparable 类型,
// 但是我们写的Student并没有实现接口Comparable ,所以发生报错
if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending
while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)
runHi++;
reverseRange(a, lo, runHi);
} else { // Ascending
while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 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
接口中只有一个方法:
java
int compareTo(T o);
方法参数与返回值:
(1)参数:T o,表示要比较的对象。
(2)返回值:
-----------返回负数:当前对象小于传入对象。
-----------返回零:当前对象等于传入对象。
-----------返回正数:当前对象大于传入对象。
语法:
java
public class 类名 implements Comparable<类名>{
@Override
public int compareTo(参数){
//...
return 返回值;
}
}
示例:
java
// Comparable<> 什么类就需要填什么
public class Student implements Comparable<Student> {
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
函数:
java
import java.util.Arrays;
class Student implements Comparable<Student>{
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()
按照年龄升序排序:
java
import java.util.Arrays;
class Student implements Comparable<Student>{
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
中添加一个加打印语句:
java
@Override
public int compareTo(Student s){
System.out.println("comppareTo()");
return this.age - s.age;
}
再次运行,结果:
很明显,使用Arrays.sort()
时调用了compareTo
函数。
2. Comparator 接口
2.1 为什么要有 Comparator 接口
一个有年龄排序方法的类:
java
class Student implements Comparable<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 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
接口中有两个常用方法:
java
int compare(T o1, T o2);
boolean equals(Object obj) //判断是否与另一个比较器相等(通常很少需要重写)
语法:
java
public class 类名 implements Comparator<需要比较类的类>{
@Override
public int compare(参数){
//...
return 返回值;
}
}
2.3 Comparator 接口的使用
- 比较两个对象的成绩:
Studnet类:
java
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 +
'}';
}
}
比较类:
java
import java.util.Comparator;
// 注意,这里的类需要填进行比较的类
class ScoreSort implements Comparator<Student>{
// 重写比较函数
// 注意,这里的参数有两个
@Override
public int compare(Student s1, Student s2){
return s1.score - s2.score;
}
}
两个对象的score进行比较:
java
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
换成排序对象即可。
java
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 |