Comparable 和 Comparator 接口以及匿名内部类与 Lambda 实现(含记忆技巧)

 ComparableComparator 经常弄混,升序降序到底该怎么实现经常搞反了??

由于当时学这两个的时候没学扎实,后边写算法的时候经常被这俩搞的头疼。

所以决定写一篇博客详解一波,一劳永逸!!!

目录

前言

1. Comparable 接口

实现 Comparable 接口

使用 Lambda 表达式实现 Comparable 接口

2. Comparator 接口

使用匿名内部类实现 Comparator 接口

使用 Lambda 表达式实现 Comparator 接口

记忆升序降序的技巧

总结



前言

他们都是用于对象排序的接口。虽然这两个接口有相似的功能,但它们在使用场景和实现方式上有些不同。这里将详细讲解 ComparableComparator,并通过匿名内部类和 Lambda 表达式的方式提供示例代码讲解。


1. Comparable 接口

Comparable 接口是一个用于定义对象的自然排序规则的接口。它有一个方法:

int compareTo(T o);

该方法返回一个整数,表示当前对象与指定对象的顺序关系:

  • 如果当前对象小于指定对象,返回负整数。
  • 如果当前对象等于指定对象,返回零。
  • 如果当前对象大于指定对象,返回正整数。

实现 Comparable 接口

假设我们有一个 Person 类,我们需要根据 age 字段对 Person 对象进行排序。首先,我们使用匿名内部类来实现 Comparable 接口。

import java.util.*;

class Person implements Comparable {
    String name;
    int age;

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

    @Override
    public int compareTo(Person other) {
        // 按照年龄升序排序
        return Integer.compare(this.age, other.age); 
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }

    public static void main(String[] args) {
        List people = Arrays.asList(
                new Person("Alice", 30),
                new Person("Bob", 25),
                new Person("Charlie", 35)
        );

        // 使用匿名内部类实现排序
        Collections.sort(people);

        // 打印排序后的结果
        System.out.println(people);
    }
}

结果:

[Person{name='Bob', age=25}, Person{name='Alice', age=30}, Person{name='Charlie', age=35}]

解释:

  1. Person 类实现了 Comparable 接口,重写了 compareTo 方法,根据 age 排序。
  2. main 方法创建了一个 List,然后使用 Collections.sort 来对列表进行排序。

使用 Lambda 表达式实现 Comparable 接口

Java 8 引入了 Lambda 表达式,它可以让代码更加简洁。在上面的示例中,我们可以使用 Lambda 表达式替代匿名内部类。

import java.util.*;

class Person implements Comparable {
    String name;
    int age;

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

    @Override
    public int compareTo(Person other) {
        return Integer.compare(this.age, other.age); 
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }

    public static void main(String[] args) {
        List people = Arrays.asList(
                new Person("Alice", 30),
                new Person("Bob", 25),
                new Person("Charlie", 35)
        );

        // 使用 Lambda 表达式实现排序
        Collections.sort(people, (p1, p2) -> p1.name.compareTo(p2.name));

        // 打印排序后的结果
        System.out.println(people);
    }
}

解释:

  1. Collections.sort 方法的第二个参数是一个 Comparator,在这里使用了 Lambda 表达式 (p1, p2) -> p1.name.compareTo(p2.name) 来进行字符串按字母顺序排序。
  2. 相较于匿名内部类,Lambda 表达式更加简洁,代码更易于理解。

2. Comparator 接口

Comparator 接口用于定义不同的排序规则,它的作用是提供一种灵活的方式来排序对象。Comparator 有多个重载方法,但最常用的是:

int compare(T o1, T o2);

ComparablecompareTo 不同,Comparator 是外部提供的排序规则,它可以与多个排序条件同时使用。

使用匿名内部类实现 Comparator 接口

我们仍然使用 Person 类,但这次我们使用 Comparator 来按年龄排序,并演示如何使用匿名内部类。

import java.util.*;

class Person {
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }

    public static void main(String[] args) {
        List people = Arrays.asList(
                new Person("Alice", 30),
                new Person("Bob", 25),
                new Person("Charlie", 35)
        );

        // 使用匿名内部类创建 Comparator
        Collections.sort(people, new Comparator() {
            @Override
            public int compare(Person p1, Person p2) {
                // 按照年龄升序排序
                return Integer.compare(p1.age, p2.age);
            }
        });

        // 打印排序后的结果
        System.out.println(people);
    }
}

解释:

  1. Collections.sort 方法接受一个 Comparator,在这里使用匿名内部类来实现按 age 排序的逻辑。
  2. 匿名内部类中的 compare 方法定义了两个 Person 对象的比较逻辑:通过 Integer.compare(p1.age, p2.age) 对年龄进行升序排序。
使用 Lambda 表达式实现 Comparator 接口

同样的例子,我们可以使用 Lambda 表达式简化 Comparator 的实现。

import java.util.*;

class Person {
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }

    public static void main(String[] args) {
        List people = Arrays.asList(
                new Person("Alice", 30),
                new Person("Bob", 25),
                new Person("Charlie", 35)
        );

        // 使用 Lambda 表达式创建 Comparator
        Collections.sort(people, (p1, p2) -> Integer.compare(p1.age, p2.age));

        // 打印排序后的结果
        System.out.println(people);
    }
}

解释:

  1. Collections.sort 的第二个参数是一个 Comparator,这里使用 Lambda 表达式 (p1, p2) -> Integer.compare(p1.age, p2.age) 来按 age 排序。
  2. Lambda 表达式更加简洁,省去了匿名内部类的冗余代码。

记忆升序降序的技巧

不要用大于小于号来比较,直接做 减法或者 compare,顺着写升序,反着写降序!!

 // 使用 Lambda 表达式创建 Comparator
    Collections.sort(people, (p1, p2) -> Integer.compare(p1.age, p2.age));
    Collections.sort(people, (p1, p2) -> p1.age - p2.age);

                                //   o1,o2,这种 1 2 的顺序就是升序,小的在前

    Collections.sort(people, (p1, p2) -> Integer.compare(p2.age, p1.age));
    Collections.sort(people, (p1, p2) -> p2.age - p1.age);

                           //同理   o2,o1,这种 2 1 的顺序就是降序序,大的在前

总结

  • Comparable:用于定义对象的自然排序规则,必须在类内部实现。通过实现 compareTo 方法来指定排序逻辑。
  • Comparator:用于在外部定义排序规则,能够灵活地实现多种排序方式。它是一个函数式接口,可以通过匿名内部类或 Lambda 表达式来实现。

秘诀  : 顺着写升序,反着写降序!!!

你可能感兴趣的:(java,开发语言)