💬 欢迎讨论:如对文章内容有疑问或见解,欢迎在评论区留言,我需要您的帮助!
👍 点赞、收藏与分享:如果这篇文章对您有所帮助,请不吝点赞、收藏或分享,谢谢您的支持!
🚀 传播技术之美:期待您将这篇文章推荐给更多对需要学习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 < 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) { // Descendingwhile (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)runHi++;reverseRange(a, lo, runHi);} else { // Ascendingwhile (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
接口中只有一个方法:
int compareTo(T o);
方法参数与返回值:
(1)参数:T o,表示要比较的对象。
(2)返回值:
-----------返回负数:当前对象小于传入对象。
-----------返回零:当前对象等于传入对象。
-----------返回正数:当前对象大于传入对象。
语法:
public class 类名 implements Comparable<类名>{@Overridepublic int compareTo(参数){//...return 返回值;}
}
示例:
// 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 方法@Overridepublic 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<Student>{public String name;public int age;public Student(String name, int age){this.name = name;this.age = age;}@Overridepublic 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<Student>{public String name;public int age;public Student(String name, int age){this.name = name;this.age = age;}@Overridepublic int compareTo(Student s){return this.age - s.age; // 升序排序}@Overridepublic 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
中添加一个加打印语句:
@Overridepublic 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<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;}@Overridepublic int compareTo(Student s){return this.age - s.age; // 升序排序}@Overridepublic 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<需要比较类的类>{@Overridepublic 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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
比较类:
import java.util.Comparator;// 注意,这里的类需要填进行比较的类
class ScoreSort implements Comparator<Student>{// 重写比较函数// 注意,这里的参数有两个@Overridepublic 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 |