目录
1.前言
2.Comaprable接口
2.1 使用细节
2.2 案例演示
3.Comparator接口
3.1 为什么需要Comparator接口
3.2 使用细节
3.3 案例演示
4.Comparable、Comparator对比
1.前言
Java 中的对象,正常情况下,只能进行比较:== 或 != 。不能使用 > 或 < 。但是在实际开发场景中,有时候需要对多个对象进行排序,言外之意,就是需要比较对象的大小。这便引出了 Comparable、Comparator 两个接口
2.Comaprable接口
Comparable 位于 java.lang.Comaprable,其源码如下:
package java.lang;
import java.util.*;
public interface Comparable<T> {public int compareTo(T o);
}
2.1 使用细节
① 实现 Comparable 接口的类必须实现 int compareTo(T o) 方法,两个对象可以通过 int compareTo(T o) 方法的返回值来比较大小:
(1)当前对象 this 大于形参对象 o,则返回正整数
(2)当前对象 this 小于形参对象 o,则返回负整数
(3)当前对象 this 等于形参对象 o,则返回 0
② 实现 Comparable 接口的对象列表或数组可以通过 Collections.sort 或 Arrays.sort 进行自动排序,无需指定 Collection.sort(...)、Arrays.sort(...) 方法的第二个比较器参数,底层会根据类中实现的 int compareTo(T o) 作为排序逻辑
③ String、八大包装类都 implements 了该接口,并实现了 int compareTo(T o) 方法,都是从小到大排列的
String:按照字符串中字符的 ASCII 值进行比较
Character:按照字符的 ASCII 值来进行比较
数值类型对应的包装类以及 BigInteger、BigDecimal :按照它们对应的数值大小进行比较
Boolean:true 对应的包装类实例大于 false 对应的包装类实例
Date、Time等:后面的日期时间比前面的日期时间大
2.2 案例演示
案例1 :根据学生的年龄对学生类型数组进行升序排序
import java.util.Arrays;
import java.util.Comparator;
public class demo {public static void main(String[] args) {Student s1 = new Student("小马", 100);Student s2 = new Student("蔡徐坤", 5);Student s3 = new Student("ftt", 90);Student[] arr1 = {s1,s2,s3};Student[] arr2 = {s1,s2,s3};System.out.println("排序前,所有学生:");Arrays.stream(arr1).forEach(student -> System.out.println(student));System.out.println("----------------------");//方式1:使用冒泡排序System.out.println("按照年龄排序:");for (int i = 1; i < arr1.length; i++) {for (int j = 0; j < arr1.length-i; j++) {if(arr1[j].compareTo(arr1[j+1])>0){Student temp = arr1[j];arr1[j] = arr1[j+1];arr1[j+1] = temp;}}}Arrays.stream(arr1).forEach(student -> System.out.println(student));System.out.println("----------------------");//方式2:使用Arrays.sort排序,因为在Student类已实现Comparable接口,所以无需指定比较器Arrays.sort(arr2);Arrays.stream(arr2).forEach(student -> System.out.println(student));}
}class Student implements Comparable<Student> {public String name;public int age;public Student(){}public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}//按学生年龄升序排序@Overridepublic int compareTo(Student anotherStudent) {if(this.age > anotherStudent.age){return 1;}else if(this.age < anotherStudent.age){return -1;}else{return 0;}}
}
案例1运行结果:
案例2 :对字符数组进行排序
import java.util.Arrays;
public class demo {public static void main(String[] args) {Character[] arr = {'b','a','c','d'};System.out.println("排序前的字符数组:"+Arrays.toString(arr));Arrays.sort(arr);//Arrays底层会将Character类中实现的 int compareTo(T o) 方法作为排序逻辑System.out.println("排序后的字符数组:"+Arrays.toString(arr));}
}
案例2运行结果:
3.Comparator接口
Comparator 接口位于 java.until.Comparator 下,其中关于 int compareTo(...) 接口的源码如下:
package java.util;public interface Comparator<T>{int compare(T o1,T o2);
}
3.1 为什么需要Comparator接口
场景 ① :当只有第三方的类时(即只有 .class 字节码文件,没有 .java 源文件,无法修改代码),且这些类没有实现 java.lang.Comparable 接口
场景 ② :类中提前实现了 Comparable 接口,指定了两个对象比较大小的规则,但此时如果不想按照它预定义的方法比较大小,但是又不能随意修改源码,因为会影响其他地方的使用,怎么办呢?
因此,基于 ①、② ,Java 增加了一个 java.util.Comparator 接口来解决问题
3.2 使用细节
① 通常是用一个单独的其他的类来实现 Comparator 接口
② 实现 Comparator 的类必须实现 int compareTo (T o1,T o2) 方法,两个对象可以通过 int compareTo (T o1,T o2) 方法的返回值来比较大小:
(1) o1 大于 o2,则返回正整数
(2) o1 小于 o2,则返回负整数
(3) o1 等于 o2,则返回 0
③ 在使用 Collection.sort 或 Arrays.sort 实现排序功能时,可以将实现了 Comparator 接口的类的实例传递给 Collection.sort 或 Arrays.sort,作为排序逻辑的比较器
3.3 案例演示
案例
import java.util.Arrays;
import java.util.Comparator;
public class demo {public static void main(String[] args) {//定义比较器实例StudentScoreComparator sc = new StudentScoreComparator();Student s1 = new Student("小马", 22,98);Student s2 = new Student("jack", 55,90);Student s3 = new Student("mary", 30,67);Student[] arr1 = {s1,s2,s3};Student[] arr2 = {s1,s2,s3};System.out.println("按分数排序前,所有学生:");Arrays.stream(arr1).forEach(student -> System.out.println(student));System.out.println("----------------------");//方式1:使用冒泡排序System.out.println("按照分数排序:");for (int i = 1; i < arr1.length; i++) {for (int j = 0; j < arr1.length-i; j++) {if(sc.compare(arr1[j],arr1[j+1]) > 0) {Student temp = arr1[j];arr1[j] = arr1[j+1];arr1[j+1] = temp;}}}Arrays.stream(arr1).forEach(student -> System.out.println(student));System.out.println("----------------------");//方式2:使用Arrays.sort排序,指定StudentScoreComparator为比较器,按学生的分数排序Arrays.sort(arr2,sc);Arrays.stream(arr2).forEach(student -> System.out.println(student));}
}//定制比较器类,按学生的分数升序排序
class StudentScoreComparator implements Comparator<Student>{@Overridepublic int compare(Student s1, Student s2) {if(s1.score > s2.score){return 1;}else if(s1.score < s2.score){return -1;}else{return 0;}}
}class Student implements Comparable<Student> {public String name;public int age;public int score;public Student(){}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 +", score=" + score +'}';}//按学生年龄升序排序@Overridepublic int compareTo(Student anotherStudent) {if(this.age > anotherStudent.age){return 1;}else if(this.age < anotherStudent.age){return -1;}else{return 0;}}
}
案例1运行结果:
4.Comparable、Comparator对比
Comparable | Comparator | |
---|---|---|
实现位置 | 类内部实现 | 外部独立实现 |
排序规则数量 | 只能定义一种排序规则 | 可根据业务求定义多种排序规则 |
侵入性 | 需要修改原类代码 | 不需要修改原类代码 |
方法 | int compareTo (T o) | int compare (T o1, T o2) |
使用场景 | 默认排序,如 Arrays.sort(arr) | 灵活排序,如 Arrays.sort(arr,comparator) |