乐趣区

关于java:面试官元素排序Comparable和Comparator有什么区别

本文已收录《Java 常见面试题》系列,Gitee 开源地址:https://gitee.com/mydb/interview

在 Java 语言中,Comparable 和 Comparator 都是用来进行元素排序的,但二者有着实质的区别。它们两也是常见的面试题,所以明天咱们一起来盘它。

1. 字面含意不同

咱们先从二者的字面含意来了解它,Comparable 翻译为中文是“比拟”的意思,而 Comparator 是“比拟器”的意思。Comparable 是以 -able 结尾的,示意它本身具备着某种能力,而 Comparator 是以 -or 结尾,示意本身是比拟的参与者,这是从字面含意先来了解二者的不同。

2. 用法不同

二者都是顶级的接口,但领有的办法和用法是不同的,上面咱们别离来看。

2.1 Comparable

Comparable 接口只有一个办法 compareTo,实现 Comparable 接口并重写 compareTo 办法就能够实现某个类的排序了,它反对 Collections.sort 和 Arrays.sort 的排序。

在咱们没有应用 Comparable 时,程序的执行是这样的:

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.ArrayList;
import java.util.List;

public class ComparableExample {public static void main(String[] args) {
        // 创建对象
        Person p1 = new Person(1, 18, "Java");
        Person p2 = new Person(2, 22, "MySQL");
        Person p3 = new Person(3, 6, "Redis");
        // 增加到汇合
        List<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        // 打印汇合信息
        list.forEach(p -> System.out.println(p.getName() +
                ":" + p.getAge()));
    }
}

// 以下 set/get/toString 都应用的是 lombok 提供的注解
@Getter 
@Setter
@ToString
class Person {
    private int id;
    private int age;
    private String name;

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

程序执行后果如下:

从上图能够看出,当自定义类 Person 没有实现 Comparable 时,List 汇合是没有排序的,只能以元素的插入程序作为输入的程序。

然而这个时候,老板有一个需要:须要依据 Person 对象的年龄 age 属性进行倒序,也就是依据 age 属性从大到小进行排序,这个时候就能够请出,咱们本文的配角:Comparable 出场了。

Comparable 的应用是在自定义对象的类中实现 Comparable 接口,并重写 compareTo 办法来实现自定义排序规定的,具体实现代码如下:

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ComparableExample {public static void main(String[] args) {
        // 创建对象
        Person p1 = new Person(1, 18, "Java");
        Person p2 = new Person(2, 22, "MySQL");
        Person p3 = new Person(3, 6, "Redis");
        // 增加对象到汇合
        List<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        // 进行排序操作 (依据 Person 类中 compareTo 中定义的排序规定)
        Collections.sort(list);
        // 输入汇合中的程序
        list.forEach(p -> System.out.println(p.getName() +
                ":" + p.getAge()));
    }
}
//  以下 set/get/toString 都应用的是 lombok 提供的注解实现的
@Getter
@Setter
@ToString
static class Person implements Comparable<Person> {
    private int id;
    private int age;
    private String name;

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

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

程序的执行后果如下图所示:

compareTo 排序办法阐明

compareTo 办法接管的参数 p 是要比照的对象,排序规定是用以后对象和要比照的对象进行比拟,而后返回一个 int 类型的值。正序从小到大的排序规定是:应用以后的对象值减去要比照对象的值;而倒序从大到小的排序规定刚好相同:是用比照对象的值减去以后对象的值。

注意事项:如果自定义对象没有实现 Comparable 接口,那么它是不能应用 Collections.sort 办法进行排序的,编译器会提醒如下谬误:

2.2 Comparator

Comparator 和 Comparable 的排序办法是不同的,Comparable 排序的办法是 compareTo,而 Comparator 排序的办法是 compare,具体实现代码如下:

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ComparatorExample {public static void main(String[] args) {
        // 创建对象
        Person p1 = new Person(1, 18, "Java");
        Person p2 = new Person(2, 22, "MySQL");
        Person p3 = new Person(3, 6, "Redis");
        // 增加对象到汇合
        List<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        // 进行排序操作 (依据 PersonComparator 中定义的排序规定)
        Collections.sort(list, new PersonComparator());
        // 输入汇合中的程序
        list.forEach(p -> System.out.println(p.getName() +
                ":" + p.getAge()));
    }
}
/**
  * 用于 Person 类的比拟器
  */
class PersonComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {return p2.getAge() - p1.getAge();}
}
@Getter
@Setter
class Person {
    private int id;
    private int age;
    private String name;

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

程序的执行后果如下图所示:

扩大:Comparator 匿名类

Comparator 除了能够通过创立自定义比拟器外,还能够通过匿名类的形式,更疾速、便捷的实现自定义比拟器的性能,具体的代码实现如下:

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class ComparatorExample {public static void main(String[] args) {
        // 构建并增加数据
        List<Person> list = new ArrayList<>();
        list.add(new Person(1, 18, "Java"));
        list.add(new Person(2, 20, "MySQL"));
        list.add(new Person(3, 6, "Redis"));
        // 应用 Comparator 匿名类的形式进行排序
        list.sort(new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {return p2.getAge() - p1.getAge();}
        });
        // 打印汇合数据
        list.forEach(p -> System.out.println(p.getName() +
                ":" + p.getAge()));
    }
}

@Getter
@Setter
static class Person {
    private int id;
    private int age;
    private String name;

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

程序的执行后果如下图所示:

3. 应用的场景不同

通过下面示例的实现代码咱们能够看出,应用 Comparable 必须要批改原有的类,也就是你要排序那个类,就要在那个中实现 Comparable 接口并重写 compareTo 办法,所以 Comparable 更像是“对内”进行排序的接口。

而 Comparator 的应用则不雷同,Comparator 无需批改原有类。也就是在最极其状况下,即便 Person 类是第三方提供的,咱们仍然能够通过创立新的自定义比拟器 Comparator,来实现对第三方类 Person 的排序功能。也就是说通过 Comparator 接口能够实现和原有类的解耦,在不批改原有类的状况下实现排序功能,所以 Comparator 能够看作是“对外”提供排序的接口。

总结

Comparable 和 Comparator 都是用来实现元素排序的,它们二者的区别如下:

  • Comparable 是“比拟”的意思,而 Comparator 是“比拟器”的意思;
  • Comparable 是通过重写 compareTo 办法实现排序的,而 Comparator 是通过重写 compare 办法实现排序的;
  • Comparable 必须由自定义类外部实现排序办法,而 Comparator 是内部定义并实现排序的。

所以用一句话总结二者的区别:Comparable 能够看作是“对内”进行排序接口,而 Comparator 是“对外”进行排序的接口。

是非审之于己,毁誉听之于人,得失安之于数。

博主介绍:80 后程序员,写博客这件事“保持”了 12 年了,喜好:读书、慢跑、羽毛球。

我的公众号:Java 面试真题解析

退出移动版