Java中Comparable与Comparator的区别

我们先来看这两个接口的定义:

//Comparable
package java.lang;
import java.util.*;

/**
This interface imposes a total ordering on the objects of each class that implements it.  This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.

Lists (and arrays) of objects that implement this interface can be sorted automatically by {@link Collections#sort(List) Collections.sort} (and {@link Arrays#sort(Object[]) Arrays.sort}). */ public interface Comparable<T> { public int compareTo(T o); }

//Comparator
package java.util;

/**
A comparison function, which imposes a total ordering on some collection of objects.  Comparators can be passed to a sort method (such as {@link Collections#sort(List,Comparator) Collections.sort} or {@link Arrays#sort(Object[],Comparator) Arrays.sort}) to allow precise control over the sort order.
*/
public interface Comparator {
    int compare(T o1, T o2);

    boolean equals(Object obj);
}

这里顺便摘了一些注释过来,可以从注释的描述上看到两个接口的作用差不多,都是用作比较或排序,并且都可以用于Collections.sort和Arrays.sort。

当然它们也有一些区别:

  • Comparable是java.lang下面的,而Comparator是java.util下面的。
  • Comparable可以说是内比较器,是需要比较的类自己去实现这个接口的方法,调用的时候也是调用类的compareTo方法;Comparator是外比较器,需要为比较的类专门写一个比较器并实现这个接口的方法,调用的时候也是调用比较器的compare方法。这里我们看到其实还有一个equals方法,但实际上我们不实现它也不会报错,这是为什么呢?因为Object类实现了该方法,我们知道,Object是所有类的父类,所以我们自己写的类也隐式地实现了该方法。

下面用具体的代码来看一下。

我们写一个简单的Person类,包含姓名和年龄。想要按照年龄大小排序。

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

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

现在来实现Comparable接口,注意如果要实现从小到大排序的话,需要保证自身比传入对象小的时候返回负数,相等的时候返回0,比传入对象大的时候返回整数。如果弄反的话会变成从大到小排序。

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

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public int compareTo(Person p) {
        return this.age - p.getAge();
    }

    public static void main(String[] args) {
        Person[] people = new Person[]{new Person("xiaoming", 20), new Person("xiaohong", 15), new Person("xiaowei", 10)};
        System.out.println("\n排序前");
        for (Person person : people) {
            System.out.print(person.getName() + ":" + person.getAge());
        }
        Arrays.sort(people);
        System.out.println("排序后");
        for (Person person : people) {
            System.out.print(person.getName() + ":" + person.getAge());
        }
    }
}

输出结果:
Java中Comparable与Comparator的区别_第1张图片

接下来试试Comparator,我们需要写一个类实现这个接口。同样是需要注意如果要实现从小到大排序,需要保证o1比o2小的时候返回负数。

public class PersonComparator implements Comparator<Person> {

    @Override
    public int compare(Person o1, Person o2) {
        return o1.getAge() - o2.getAge();
    }
}
public class Person {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public static void main(String[] args) {
        Person[] people = new Person[]{new Person("xiaoming", 20), new Person("xiaohong", 15), new Person("xiaowei", 10)};
        System.out.println("排序前");
        for (Person person : people) {
            System.out.print(person.getName() + ":" + person.getAge());
        }
        Arrays.sort(people, new PersonComparator());
        System.out.println("\n排序后");
        for (Person person : people) {
            System.out.print(person.getName() + ":" + person.getAge());
        }
    }
}

输出结果:
Java中Comparable与Comparator的区别_第2张图片

可以看到调用Arrays.sort的时候额外传入了我们自定义的比较器。

那什么时候该用Comparable什么时候该用Comparator呢?个人认为并没有什么差别。如果想实现类的自比较或调用Arrays.sort等方法时或希望传入SortedMap等有序结构时可以自动排序的时候,可以在类中实现Comparable接口;当无法修改一个类的代码或类自身已经实现了Comparable接口的时候,我们可以选择实现一个Comparator比较器从外部去比较,比如对于Integer类,我们如果想按照绝对值大小排序的话,就可以实现一个Comparator。

你可能感兴趣的:(学习笔记)