Comparable和Comparator比较

Comparable定义:
  • Comparable是一个排序接口,当一个类实现了该接口,就意味着“该类支持排序”。

具体实现:

package java.lang;
import java.util.*;
public interface Comparable {
    public int compareTo(T o);
}

我们可以看到它是通过compareTo方法来进行排序的。

假设我们通过 x.compareTo(y) 来“比较x和y的大小”。
若返回“负数”,意味着“x比y小”;返回“零”,意味着“x等于y”;返回“正数”,意味着“x大于y”。

Comparator定义:
  • Comparator为比较器接口,若要实现某个本身不支持排序的类,可以通过定义定义一个Comparator接口来实现类的排序。

具体实现:

package java.util;
public interface Comparator {
    int compare(T o1, T o2);
    boolean equals(Object obj);
  • 若一个类要实现Comparator接口:它一定要实现compareTo(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。

为什么可以不实现 equals(Object obj) 函数呢?
因为任何类,默认都是已经实现了equals(Object obj)的。 Java中的一切类都是继承于java.lang.Object,在Object.java中实现了equals(Object obj)函数;所以,其它所有的类也相当于都实现了该函数。

  • int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。
Comparable和Comparator的比较:

共同点:Comparable & Comparator 都是用来实现集合中元素的比较、排序的。当我们定义的某个类需要进行排序时,就要考虑实现Comparable或Comparator接口。

我们定义一个Person,要求其根据id进行排序:

实现Comparable接口

public class Person implements Comparable{
    private int id;
    private String name;
    private int age;

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

    @Override
    public int compareTo(Person o) {
        return this.id - o.id;
    }

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

    public static void main(String[] args){
        List list = new ArrayList<>();
        list.add(new Person(3,"John",18));
        list.add(new Person(1,"Marry",21));
        list.add(new Person(2,"Tom",20));
        System.out.println("Before sort:");
        printList(list);
        Collections.sort(list);
        System.out.println("After sort:");
        printList(list);
    }

    public static void printList(List list){
        for (Person p : list){
            System.out.print(p + " / ");
        }
        System.out.println();
    }
}

输出结果:
Before sort:
id: 3 name: John  age: 18 / id: 1 name: Marry  age: 21 / id: 2 name: Tom  age: 20 / 
After sort:
id: 1 name: Marry  age: 21 / id: 2 name: Tom  age: 20 / id: 3 name: John  age: 18 /

我们可以看到person类中实现了Comparable接口,并重写了CompareTo方法。

实现Comparator接口

public class Person{
    private int id;
    private String name;
    private int age;

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

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

    public static void main(String[] args){
        List list = new ArrayList<>();
        list.add(new Person(3,"John",18));
        list.add(new Person(1,"Marry",21));
        list.add(new Person(2,"Tom",20));
        System.out.println("Before sort:");
        printList(list);
        //调用sort函数,并传入自定义Comparator
        Collections.sort(list,new MyComparator());
        System.out.println("After sort:");
        printList(list);
    }
    
    //自定义Comparator接口,并重写compare方法
    private static class MyComparator implements Comparator{

        @Override
        public int compare(Person o1, Person o2) {
            return o1.id - o2.id;
        }
    }

    private static void printList(List list){
        for (Person p : list){
            System.out.print(p + " / ");
        }
        System.out.println();
    }
}

通过上面的两种实现方式:

区别:

  • Comparable接口是在集合内部定义的方法实现的排序。
  • Comparator接口是在集合外部实现的排序。
  • 简单来说,comparable接口是通过类自己完成比较,而comparator接口是通过外部程序实现比较。

若同时实现Comparable接口和Comparator接口,排序会听哪个的呢?

我们设置Comparable接口实现升序,而Comparator接口实现降序。

public class Person implements Comparable{
    private int id;
    private String name;
    private int age;

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

    @Override
    public int compareTo(Person o) {
        return id - o.id;
    }

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

    public static void main(String[] args){
        List list = new ArrayList<>();
        list.add(new Person(3,"John",18));
        list.add(new Person(1,"Marry",21));
        list.add(new Person(2,"Tom",20));
        System.out.println("Before sort:");
        printList(list);
        //调用sort函数,并传入自定义Comparator
        Collections.sort(list,new MyComparator());
        System.out.println("After sort:");
        printList(list);
    }



    //自定义Comparator接口,并重写compare方法
    private static class MyComparator implements Comparator{

        @Override
        public int compare(Person o1, Person o2) {
            return o2.id - o1.id;
        }
    }

    private static void printList(List list){
        for (Person p : list){
            System.out.print(p + " / ");
        }
        System.out.println();
    }
}

输出结果:
Before sort:
id: 3 name: John  age: 18 / id: 1 name: Marry  age: 21 / id: 2 name: Tom  age: 20 / 
After sort:
id: 3 name: John  age: 18 / id: 2 name: Tom  age: 20 / id: 1 name: Marry  age: 21 / 

我们可以看到,最后的结果是以降序方式输出的。也就意味着comparator接口优先于comparable接口。

实际上,对于sort排序方法,若传入自定义的comparator接口,则会以传入的comparator方法来实现排序,否则,会使用类本身的comparable接口方法。

何时使用comparable,何时使用comparator?
  • 若我们在对要排序的类的排序规则比较固定,也就是不常修改时,我们考虑实现comparable接口。
  • 若我们对要排序的类的排序规则是经常变化的,那么我们考虑实现comparator接口。

你可能感兴趣的:(Comparable和Comparator比较)