java--Java 中的排序:Comparable 与 Comparator 的使用与区别

1. 背景

在 Java 中,如果我们希望自定义类能够进行排序(例如在集合、数组中排序),就需要定义对象的比较规则。

Java 提供了两种方式:

  • Comparable<T> 接口 → 在类内部实现,定义对象的“自然顺序”。

  • Comparator<T> 接口 → 在类外部定义比较器,可以灵活指定不同的排序规则。


2. Comparable 接口

        Java 中很多常用类都实现了 Comparable 接口,例如 StringInteger

public class CompareToDemo {
    public static void main(String[] args) {
        // String 按字典序比较
        System.out.println("apple".compareTo("banana")); // -1
        System.out.println("dog".compareTo("dog"));      // 0
        System.out.println("zoo".compareTo("apple"));    // 正数

        // Integer 按数值大小比较
        Integer a = 10, b = 20;
        System.out.println(a.compareTo(b)); // -1
        System.out.println(b.compareTo(a)); // 1
        System.out.println(a.compareTo(10));// 0
    }
}

2.1 定义

public interface Comparable<T> {
    int compareTo(T o);
}

2.2 返回值含义

  • 负数:当前对象 < 参数对象

  • 0:当前对象 == 参数对象

  • 正数:当前对象 > 参数对象

2.3 使用场景

当一个类本身就有固定的“自然排序规则”,可以直接实现 Comparable


3. Comparator 接口

3.1 定义

public interface Comparator<T> {
    int compare(T o1, T o2);
}

3.2 返回值含义

Comparable 相同:

  • 负数 → o1 < o2

  • 0 → o1 == o2

  • 正数 → o1 > o2

3.3 使用场景

当我们不想修改类本身,或者需要定义多种排序规则时,使用 Comparator 更灵活。


4. Comparable vs Comparator 区别表

特性ComparableComparator
方法int compareTo(T o)int compare(T o1, T o2)
定义位置内部(实现接口)外部(单独写比较器)
排序规则数量一种(自然顺序)多种(可定义多个 Comparator)
修改类代码需求需要修改类本身不需要修改类本身
常见使用场景Collections.sort(list)Collections.sort(list, comparator)

5. 示例:对 List<Student>age 排序

5.1 使用 Comparable

class Student implements Comparable<Student> {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 定义“自然顺序”:按年龄升序
    @Override
    public int compareTo(Student other) {
        return Integer.compare(this.age, other.age);
    }

    @Override
    public String toString() {
        return name + "(" + age + ")";
    }
}

public class ComparableDemo {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student("Alice", 22));
        list.add(new Student("Bob", 18));
        list.add(new Student("Charlie", 20));

        // 使用 Comparable 定义的 compareTo 方法排序
        Collections.sort(list);

        System.out.println(list); 
        // 输出: [Bob(18), Charlie(20), Alice(22)]
    }
}

5.2 使用 Comparator

如果我们不想修改 Student 类,或者想要不同的排序规则,可以使用 Comparator

方式一:匿名内部类
Collections.sort(list, new Comparator<Student>() {
    @Override
    public int compare(Student s1, Student s2) {
        return Integer.compare(s1.getAge(), s2.getAge());
    }
});
方式二:Lambda 表达式(Java 8+ 推荐
list.sort((s1, s2) -> Integer.compare(s1.getAge(), s2.getAge()));
方式三:方法引用(更简洁)
list.sort(Comparator.comparing(Student::getAge));

👉 输出结果同样是:

[Bob(18), Charlie(20), Alice(22)]

6. 多条件排序(进阶)

6.1使用Comparator 实现多条件排序

使用 Comparator 时,可以轻松实现多条件排序。


例如:先按年龄升序,再按名字字母序升序

//方式一、方法引用 + 链式 Comparator
list.sort(
    Comparator.comparing(Student::getAge)
              .thenComparing(Student::getName)
);

//方式二、匿名内部类写法
list.sort(new Comparator<Student>() {
    @Override
    public int compare(Student s1, Student s2) {
        // 先按年龄排序
        int result = Integer.compare(s1.getAge(), s2.getAge());
        // 如果年龄相同,则按姓名排序
        if (result == 0) {
            result = s1.getName().compareTo(s2.getName());
        }
        return result;
    }
});


//方式三、Lambda 表达式写法(Java 8+ 推荐)
list.sort((s1, s2) -> {
    int result = Integer.compare(s1.getAge(), s2.getAge());
    if (result == 0) {
        result = s1.getName().compareTo(s2.getName());
    }
    return result;
});


6.2 那是不是不能使用Comparable完成多条件呢?

1️⃣ Comparable 的特点
  • Comparable自然排序(对象自己规定的排序规则)。

  • 一个类 只能实现一次 compareTo 方法,也就是说只能有一种排序逻辑。

  • 例子:

public class Student implements Comparable<Student> {
    private int age;
    private String name;

    @Override
    public int compareTo(Student other) {
        // 先按年龄,再按姓名
        int result = Integer.compare(this.age, other.age);
        if (result == 0) {
            result = this.name.compareTo(other.name);
        }
        return result;
    }
}

👉 这样就能实现 多条件排序,但限制是 Student 这个类就被固定死了,始终用这一套排序规则


2️⃣ Comparator 的特点
  • Comparator外部比较器,不修改实体类本身。

  • 可以定义多个不同的排序规则,根据需要随时切换。

  • 例子:

Comparator<Student> byAgeThenName = 
    Comparator.comparing(Student::getAge)
              .thenComparing(Student::getName);

Comparator<Student> byNameThenAge = 
    Comparator.comparing(Student::getName)
              .thenComparing(Student::getAge);

👉 这样一个类(Student)就可以有 多种排序方式,灵活性更高。


3️⃣ 多条件的对比
  • Comparable:类内部定义,固定一种排序逻辑(可以写多条件,但只能有这一种)。

  • Comparator:类外部定义,可以有多种排序逻辑,灵活组合,推荐用于多条件排序。

👉 这样就能实现 多条件排序,但限制是 Student 这个类就被固定死了,始终用这一套排序规则

        ✅ 多条件排序,Comparable 也能实现(在 compareTo 里写多条件逻辑)。
        ❌ 但是 Comparable 只能有这一种排序方式,灵活性差。
        👉 真正业务里,一般 多条件排序都会用 Comparator


7. 总结

  • Comparable:让类具备自然排序能力,适合“唯一固定规则”的场景。

  • Comparator:外部比较器,适合需要定义多种排序规则的场景。

  • 对于 List<Student>

    • 如果 Student 类实现了 Comparable,直接用 Collections.sort(list)

    • 如果不想改 Student 类,可以用 Comparator 方式排序。

  • 推荐使用 Comparator.comparing(...) + Lambda/方法引用,更简洁灵活。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值