Comparable和Comparator比较

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

具体实现:

package java.lang;
import java.util.*;
public interface Comparable<T> {
    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<T> {
    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<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 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<Person> 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<Person> 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<Person> 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<Person>{

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

    private static void printList(List<Person> 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<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 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<Person> 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<Person>{

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

    private static void printList(List<Person> 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接口。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,540评论 11 349
  • Java集合框架 Java平台提供了一个全新的集合框架。“集合框架”主要由一组用来操作对象的接口组成。不同接口描述...
    小石38阅读 3,021评论 0 0
  • 项目中经常会遇到列表搜索查询,大部分的查询是可以通过sql语句来实现的,有些特殊的搜索排序sql则实现不了,例如中...
    信徒_allen阅读 7,458评论 0 1
  • Java中提供了两种对集合或数组中元素进行排序的方法,一种是实现Comparable接口,另一种是实现Compar...
    EakonZhao阅读 12,731评论 0 9
  • 前面两种方式(plist文件读写、NSUserDefaults偏好设置)只能保存 plist 支持的基本数据类型,...
    伯牙呀阅读 5,824评论 2 3

友情链接更多精彩内容