【JAVA】深入浅出明确Comparator 和 Comparable接口

张春  金牌会员 | 2025-3-19 23:19:56 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 982|帖子 982|积分 2946


提示:以下是本篇文章正文内容,下面案例可供参考
一、Comparable 接口

概述

Comparable 是一个泛型接口,用于界说对象的自然排序(natural ordering)。当你盼望类的对象能够被排序时,可以让该类实现Comparable 接口,并重写 compareTo 方法来指定排序规则。
方法

int compareTo(T o): 比力当前对象与指定对象的次序。
返回值为:
负数: 表示当前对象小于指定对象。
零: 表示两个对象相等。
正数: 表示当前对象大于指定对象。
假设我们有一个 Person 类,我们盼望通过年事对 Person 对象举行排序:
  1. public class Person implements Comparable<Person> {
  2.     private String name;
  3.     private int age;
  4.     public Person(String name, int age) {
  5.         this.name = name;
  6.         this.age = age;
  7.     }
  8.     @Override
  9.     public int compareTo(Person other) {
  10.         // 根据年龄升序排序
  11.         return Integer.compare(this.age, other.age);
  12.     }
  13.     @Override
  14.     public String toString() {
  15.         return "Person{name='" + name + "', age=" + age + '}';
  16.     }
  17.     public static void main(String[] args) {
  18.         List<Person> people = Arrays.asList(
  19.             new Person("Alice", 30),
  20.             new Person("Bob", 25),
  21.             new Person("Charlie", 35)
  22.         );
  23.         Collections.sort(people); // 使用自然排序
  24.         people.forEach(System.out::println);
  25.     }
  26. }
复制代码
二、Comparator 接口

概述

Comparator 接口提供了一种机动的方式来界说对象之间的排序规则,而无需修改类本身。这对于那些你无法修改源代码的类或需要多种排序逻辑的情况非常有用。
方法

int compare(T o1, T o2):
比力两个对象以确定它们的次序。返回值的含义与 Comparable 的 compareTo 方法类似。
boolean equals(Object obj): 指示此比力器是否等于指定对象。通常不需要覆盖此方法,除非有特殊需求。
此外,从 Java 8 开始,Comparator 接口还提供了一些默认方法和静态方法来简化比力器的创建和组合,例如:
default Comparator reversed(): 返回一个与此比力器相反次序的比力器。
static <T, U extends Comparable<? super U>> Comparator comparing(Function<? super T, ? extends U> keyExtractor): 接受一个提取键的函数并返回一个基于该键的比力器。
default Comparator thenComparing(Comparator<? super T> other): 链式添加额外的排序条件。
假设我们需要根据名字而不是年事对 Person 对象举行排序,我们可以界说一个 Comparator:
  1. import java.util.*;
  2. public class Person {
  3.     private String name;
  4.     private int age;
  5.     public Person(String name, int age) {
  6.         this.name = name;
  7.         this.age = age;
  8.     }
  9.     public String getName() {
  10.         return name;
  11.     }
  12.     public int getAge() {
  13.         return age;
  14.     }
  15.     @Override
  16.     public String toString() {
  17.         return "Person{name='" + name + "', age=" + age + '}';
  18.     }
  19.     public static void main(String[] args) {
  20.         List<Person> people = Arrays.asList(
  21.             new Person("Alice", 30),
  22.             new Person("Bob", 25),
  23.             new Person("Charlie", 35)
  24.         );
  25.         // 使用自定义的Comparator
  26.         Comparator<Person> byName = (p1, p2) -> p1.getName().compareTo(p2.getName());
  27.         people.sort(byName);
  28.         people.forEach(System.out::println);
  29.     }
  30. }
复制代码
输出结果将是按名字字母次序分列的 Person 列表。
三、 团结使用

有时你可能需要团结 Comparable 和 Comparator 来实现更复杂的排序逻辑。比如先按年事降序排序,然后在年事类似的情况下按名字升序排序:
  1. import java.util.*;
  2. import java.util.stream.Collectors;
  3. public class Person implements Comparable<Person> {
  4.     private String name;
  5.     private int age;
  6.     public Person(String name, int age) {
  7.         this.name = name;
  8.         this.age = age;
  9.     }
  10.     @Override
  11.     public int compareTo(Person other) {
  12.         // 默认按年龄升序排序
  13.         return Integer.compare(this.age, other.age);
  14.     }
  15.     public String getName() {
  16.         return name;
  17.     }
  18.     public int getAge() {
  19.         return age;
  20.     }
  21.     @Override
  22.     public String toString() {
  23.         return "Person{name='" + name + "', age=" + age + '}';
  24.     }
  25.     public static void main(String[] args) {
  26.         List<Person> people = Arrays.asList(
  27.             new Person("Alice", 30),
  28.             new Person("Bob", 25),
  29.             new Person("Charlie", 35),
  30.             new Person("David", 30)
  31.         );
  32.         // 先按年龄降序,再按名字升序排序
  33.         people.sort(Comparator.comparingInt(Person::getAge).reversed()
  34.                 .thenComparing(Person::getName));
  35.         people.forEach(System.out::println);
  36.     }
  37. }
复制代码
在这个例子中,我们起首通过 Comparator.comparingInt(Person::getAge).reversed() 创建了一个按年事降序排序的比力器,然后通过 .thenComparing(Person::getName) 添加了一个次级排序条件,即在年事类似的情况下按名字升序排序。
四、基本类型的包装类及其 compare 方法

实际上,对于基本数据类型的比力,Java提供了相应的包装类,并且每个都有类似的静态 compare 方法。此外,标准库中的某些聚集类型(如 TreeSet, TreeMap)使用了 Comparator 来举行元素的比力,但它们本身并不实现 compare 方法。
基本类型的包装类及其 compare 方法

Java的基本类型对应的包装类都提供了静态的 compare 方法来比力相应类型的两个值:
Integer

static int compare(int x, int y)
Long

static int compare(long x, long y)
Float

static int compare(float f1, float f2)
Double

static int compare(double d1, double d2)
Short

static int compare(short s1, short s2)
Byte

static int compare(byte b1, byte b2)
Character

static int compare(char x, char y)
Boolean

没有直接的 compare 方法,由于布尔值只有两种状态 (true 和 false),可以直接通过逻辑运算符举行比力。
这些方法简化了基本类型之间的比力操作,制止了手动编写比力逻辑(例如制止直接使用减法可能导致的溢出问题)。
聚集框架中的比力

尽管基本类型的包装类提供了 compare 方法,但在聚集框架中,更常见的做法是使用 Comparator 接口或让元素类型实现 Comparable 接口来举行自界说排序。以下是一些相关的聚集类型:
TreeSet:

一个有序聚集,它要么要求其元素实现 Comparable 接口,要么在创建时提供一个 Comparator。
TreeMap:

一个键值对映射表,此中键保持有序。同样地,它也要求键实现 Comparable 或者在构造时提供一个 Comparator。
PriorityQueue:

一个优先级队列,默认情况下基于自然次序(如果元素实现了 Comparable),也可以在创建时指定一个 Comparator。
  1. import java.util.Comparator;
  2. import java.util.TreeSet;
  3. public class Main {
  4.     public static void main(String[] args) {
  5.         TreeSet<Integer> numbers = new TreeSet<>(Comparator.reverseOrder()); // 使用逆序比较器
  6.         numbers.add(1);
  7.         numbers.add(2);
  8.         numbers.add(3);
  9.         System.out.println(numbers); // 输出 [3, 2, 1]
  10.     }
  11. }
复制代码
总结

Comparable: 适用于界说类的自然排序规则,要求类实现 Comparable 接口,并重写 compareTo 方法。
Comparator: 提供了更大的机动性,允许你在不修改类的情况下界说不同的排序规则。可以通过匿名内部类、lambda 表达式或方法引用来创建比力器,并且支持链式调用多个比力条件。
选择哪种方式取决于具体的应用场景。如果你只需要一种固定的排序方式,Comparable 可能更符合;如果需要多种排序方式或者无法修改原类,则应使用 Comparator。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张春

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表