java 实现Comparable接口和实现Comparator接口排序的区别

发布于:2024-07-11 ⋅ 阅读:(26) ⋅ 点赞:(0)

Comparable接口

  1. 作用
    • Comparable接口是在类的内部实现的,用于指定类的默认比较规则。
    • 当一个类实现了Comparable接口时,它必须实现compareTo方法,该方法用于定义对象之间的自然顺序。
  2. 实现方式
    • 实现Comparable接口的类必须重写compareTo方法,该方法返回一个整数值,表示当前对象与另一个对象的比较结果。
  3. 使用场景
    • 当你需要定义类的默认排序方式时,应该实现Comparable接口。
    • 例如,对于String类,排序时通常使用字典顺序,因此String类实现了Comparable接口。
  4. 举例:
public class Person implements Comparable<Person>{
    private int age;
    private String name;
    Person(int age,String name){
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }
    @Override
    public int compareTo(Person o) {
        return this.age-o.age;
    }

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

public static void main(String[] args) {
    List<Person> personList = new ArrayList<>();
    personList.add(new Person(15, "zhangsan"));
    personList.add(new Person(12, "lisi"));
    personList.add(new Person(17, "wangwu"));
    System.out.println("排序前");
    System.out.println(personList);
    System.out.println("排序后");
    Collections.sort(personList);
    System.out.println(personList);
}

运行结果
在这里插入图片描述

Comparator接口

  1. 作用
    • Comparator接口是在类的外部实现的,它允许你实现多种不同的排序规则。
    • 通过Comparator,你可以在不修改类本身的情况下,实现多种不同的排序方式。
  2. 实现方式
    • Comparator接口包含一个compare方法,用于比较两个对象的顺序。
    • 通常在创建对象实例时,可以传递一个Comparator对象,用于定义对象的排序方式。
  3. 使用场景
    • 当你需要对某个类的对象进行多种不同的排序时,应该使用Comparator接口。
    • 例如,对于一个Person类,可能需要根据年龄、姓名等字段进行不同的排序,这时就可以创建不同的Comparator实现来实现不同的排序规则。
  4. 举例:
class MyComparator implements Comparator<Person>{
    @Override
    public int compare(Person o1, Person o2) {
        return o2.getAge()-o1.getAge();
    }
}

public static void main(String[] args) {
     List<Person> personList = new ArrayList<>();
     personList.add(new Person(15, "zhangsan"));
     personList.add(new Person(12, "lisi"));
     personList.add(new Person(17, "wangwu"));
     System.out.println("排序前");
     System.out.println(personList);
     System.out.println("排序后");
     //下面可以简写为personList.sort(new MyComparator());
     Collections.sort(personList,new MyComparator());
     System.out.println(personList);
}

运行结果:
在这里插入图片描述

  1. 为了防止误以为是实现Comparable接口才拍的序,这里使用了降序排列

总结:要比较的类实现Comparable接口后只能通过实现的compareTo方法中特定的比较规则进行比较,如果该类有不同的比较需求则没办法满足(例如学生类在A场景下需要按照年龄进行排序,在B场景中需要按照姓名进行排序),Comparator接口不需要比较的类去实现可以根据不同的比较需求自定义不同的比较规则因此更加灵活。

两种方式都实现了,那种的优先级更高?

这取决于Collections.sort()方法是否传入了自定义Comparator排序规则,如果传入了自定义Comparator排序规则那以Comparator为准否则以Comparable为准。

集合可以用Collections.sort()来排序,那数组呢?

对于数组而言可以使用Arrays.sort()来排序,和Collections.sort一样也支持传递自定义排序规则

示例:

Person[] peopleArray = new Person[] { ... }; // 假设这里有一个Person类的数组
Arrays.sort(peopleArray); // 默认按照Person类的compareTo方法(例如按年龄)进行排序
Arrays.sort(peopleArray, new MyComparator()); // 使用自定义的比较器按姓名排序

Set集合如何排序?

Set集合的特点是,无序且元素不能重复,通常情况下是不能直接使用Collections.sort方法来排序的,因为Set接口本身并没有提供排序的保证,如果你希望对Set中的元素进行排序,一般的做法是将Set转换为List,然后再对List进行排序。这样做的好处是可以利用Collections.sort方法来对List进行排序,因为List接口支持有序的元素集合。

示例:

Set<Person> personSet = new HashSet<>(); // 假设这里有一个存放Person类对象的Set集合
personSet.add(new Person(15, "zhangsan"));
personSet.add(new Person(12, "lisi"));
personSet.add(new Person(17, "wangwu"));

// 将Set转换为List
List<Person> personList = new ArrayList<>(personSet);

// 使用Collections.sort对List进行排序
Collections.sort(personList, new MyComparator()); // 使用自定义的比较器按姓名排序

那是所有的Set集合都需要转为List来进行排序吗?有没有特例?

不是所有的Set集合都需要转换为List来排序。在Java中,Set接口的实现类通常有不同的排序保证和特性,具体取决于具体的实现类。下面来介绍常见的Set接口实现类及其排序特性:

  1. HashSet
    • HashSet不保证元素的顺序,因此无法直接使用Collections.sort方法进行排序。如果需要对HashSet中的元素进行排序,首先需要将其转换为List,然后再进行排序。
  2. LinkedHashSet
    • LinkedHashSet保持元素插入的顺序,即元素迭代的顺序与插入顺序一致。可以将LinkedHashSet转换为List,然后利用Collections.sort对List进行排序。
  3. TreeSet
    • TreeSet是按照元素的自然顺序或者通过提供的Comparator进行排序的。因此,如果使用TreeSet存储元素,并且在构造TreeSet时提供了Comparator,那么TreeSet中的元素会按照指定的排序规则进行排序,无需额外的步骤。

示例代码如下所示:

// 使用TreeSet并提供Comparator来存储Person对象
Set<Person> personSet = new TreeSet<>(new MyComparator());
personSet.add(new Person(15, "zhangsan"));
personSet.add(new Person(12, "lisi"));
personSet.add(new Person(17, "wangwu"));

// 因为TreeSet已经按照MyComparator中的排序规则排序,直接打印即可
for (Person person : personSet) {
    System.out.println(person);
}

compare方法返回值说明

  • 返回负数:表示第一个参数应排在第二个参数之前(升序)。
  • 返回零:表示两个参数相等。
  • 返回正数:表示第一个参数应排在第二个参数之后(升序)。

因此,如果你希望实现升序排序,你需要确保在 compare 方法中返回负数或零。如果返回正数,则会导致降序排序。