Java 基础 --- Comparable 和 Comparator
Comparable 接口
- comparable接口只有一个方法 —
compareTo(T o)
- 一个类实现 Comparable 接口并重写 compareTo 方法就可以支持
Collections.sort
和Arrays.sort
的排序- 返回值 — 从小到大排序:
- 如果当前对象this大于形参对象obj,则返回正整数;
- 如果当前对象this小于形参对象obj,则返回负整数;
- 如果当前对象this等于参数对象obj,则返回零。
- this - input (从小到大排序) , input - this (从大到小排序)
- example:
- 从大到小
p.getAge() - this.getAge()
- 从小到大
this.getAge() - p.getAge()
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class Person implements Comparable<Person> {
private int id;
private int age;
private String name;
public Person(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
//重写compareTo, 使用 `Collections.sort` 和 `Arrays.sort` 的时候就可以根据年龄从大到小排序
//如果从小到大排序, 则 this.getAge() - p.getAge();
@Override
public int compareTo(Person p) {
return p.getAge() - this.getAge();
}
}
public class ComparableExample {
public static void main(String[] args) {
Person p1 = new Person(1, 18, "Java");
Person p2 = new Person(2, 22, "MySQL");
Person p3 = new Person(3, 6, "Redis");
List<Person> list = new ArrayList<>();
list.add(p1);
list.add(p2);
list.add(p3);
// 进行排序操作(根据 Person 类中 compareTo 中定义的排序规则)
Collections.sort(list);
}
}
Another example:
//指明商品比较大小的方法,按照价格从低到高,如果价格相同,按照产品名称从低到高
@Override
public int compareTo(Object o) {
if(o instanceof Goods){
Goods goods=(Goods) o;
if(this.price>goods.price){
return 1;
}else if(this.price<goods.price){
return -1;
}else{
//价格相同,按照产品名称从低到高比较
return this.name.compareTo(goods.name);
}
Comparator 接口
- comparatro接口包含很多方法, 其中排序的方法是
compare(T o1, T o2)
- 默认为从小到大排序,用参数o1减参数o2。若需要从大到小排序,则用参数o2减参数o1
- 重写Comparator接口有三种方法
- 使用内部静态类
- 使用内部匿名类
- 使用lambda表达式
使用内部静态类
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparatorExample {
/**
* 用于 Person 类的比较器
*/
static class PersonComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p2.getAge() - p1.getAge();
}
}
public static void main(String[] args) {
// 创建对象
Person p1 = new Person(1, 18, "Java");
Person p2 = new Person(2, 22, "MySQL");
Person p3 = new Person(3, 6, "Redis");
// 添加对象到集合
List<Person> list = new ArrayList<>();
list.add(p1);
list.add(p2);
list.add(p3);
// 进行排序操作(根据 PersonComparator 中定义的排序规则)
Collections.sort(list, new PersonComparator());
}
}
重写Comparator — Arrays.sort()
- 重写comparator使Arrays.sort可以对二维数组从小到大排序
//内部匿名类
Arrays.sort(nums, new Comparator<int[]>() {
public int compare(int[] a, int[] b){
if(a[0]==b[0]){
return a[1] - b[1];
}else {
return a[0] - b[0];
}
}
});
//lambda表达式
Arrays.sort(intervals,(int [] o1, int [] o2)->{
return o1[0]-o2[0];
});
重写Comparator — PriorityQueue()
class Node {
public int num;
public int freq;
public Node(int num, int freq) {
this.num = num;
this.freq = freq;
}
}
public int[] topKFrequent(int[] nums, int k) {
//重写heap的comparator, heap将根据freq从大到小排序
//内部匿名类
PriorityQueue<Node> heap = new PriorityQueue<>(new Comparator<Node>() {
@Override
public int compare(Node o1, Node o2) {
return o2.freq - o1.freq;
}
});
//lambda表达式
PriorityQueue<Integer> priorityQueue2 = new PriorityQueue<>((Integer o1, Integer o2) -> {
return o2 - o1;
});
}
Comparable 和 Comparator的区别
- 使用 Comparable 必须要修改原有的类,也就是你要排序那个类,就要在那个中实现 Comparable 接口并重写 compareTo 方法
- 而 Comparator 的使用则不相同,Comparator 无需修改原有类。也就是在最极端情况下,即使 Person 类是第三方提供的,我们依然可以通过创建新的自定义比较器 Comparator,来实现对第三方类 Person 的排序功能。也就是说通过 Comparator 接口可以实现和原有类的解耦,在不修改原有类的情况下实现排序功能,