JAVA——Comparable接口和Comparator接口的区别

JAVA——Comparable接口和Comparator接口的区别

Comparable接口

Comparable是一个排序接口。若一个类实现了Comparable接口,即代表该类实现了compareTo方法,该方法规定了该类的对象的比较规则(两个对象如何比较“大小”)。
类通过实现o1.compareTo(o2)方法来比较o1o2的大小:

  • 若返回正数,意味着o1大于o2
  • 若返回负数,意味着o1小于o2
  • 若返回零,则意味着o1等于o2

Comparator接口

Comparator是比较器接口。若我们只需要控制某些对象的次序,而类本身并不支持排序(即没有实现Comparable接口),对于这种情况,我们可以通过建立一个比较器(即关于该类的一个Comparator接口实现类)来进行排序。
比较器需实现方法compare(T o1, T o2),其原理与上面的o1.compareTo(o2)方法类似,这里就不再描述。

两者的联系

Comparable接口实现在自身类中,代表默认排序,相当于内部比较器;而Comparator接口则是为类外实现的一个比较器,相当于外部比较器

案例加深理解

用于比较的自定义Student类:

public class Student implements Comparable<Student> {
     
    private String name;
    private int grade;

    public Student() {
     }
    
    public Student(String name, int grade) {
     
        this.name = name;
        this.grade = grade;
    }

    public void setName(String name) {
     
        this.name = name;
    }

    public void setGrade(int grade) {
     
        this.grade = grade;
    }

    public String getName() {
     
        return name;
    }

    public int getGrade() {
     
        return grade;
    }

    @Override
    public String toString() {
     
        return "Student{" +
                "name='" + name + '\'' +
                ", grade=" + grade +
                '}';
    }

    @Override
    @Override
    public int compareTo(Student o) {
     
        return this.getGrade() > o.getGrade() ? 1 : this.getGrade() < o.getGrade() ? -1 : this.getName().compareTo(o.getName());
    }
}

上述Student类实现了Comparable接口,带有默认排序,调试代码如下:

public class Main {
     
    public static void main(String[] args) {
     
        List<Student> arr = new ArrayList<>();
        arr.add(new Student("John", 100));
        arr.add(new Student("Bob", 75));
        arr.add(new Student("Alice", 100));
        arr.add(new Student("Jake", 90));
        System.out.println(arr);
        System.out.println("------------------------");
        Collections.sort(arr);  //默认排序
        System.out.println(arr);
        
    }
}

另外定义一个实现Compartor接口的比较器如下:

public class StuCompartor implements Comparator<Student> {
     
    @Override
    public int compare(Student o1, Student o2) {
     
        return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
    }
}

调试代码:

public class StuMain {
     
    public static void main(String[] args) {
     
        List<Student> arr = new ArrayList<>();
        arr.add(new Student("John", 100));
        arr.add(new Student("Bob", 75));
        arr.add(new Student("Alice", 100));
        arr.add(new Student("Jake", 90));
        System.out.println(arr);
        System.out.println("------------------------");
        Collections.sort(arr, new StuCompartor());//外部比较器
        System.out.println(arr);
    }
}

运行结果均如下所示:

[Student{
     name='John', grade=100}, Student{
     name='Bob', grade=75}, Student{
     name='Alice', grade=100}, Student{
     name='Jake', grade=90}]
------------------------
[Student{
     name='Bob', grade=75}, Student{
     name='Jake', grade=90}, Student{
     name='Alice', grade=100}, Student{
     name='John', grade=100}]

扩展

若只排序一次,则可不额外定义比较器,直接利用匿名内部类即可:

Collections.sort(arr, new Comparator<Student>() {
     
    @Override
    public int compare(Student o1, Student o2) {
     
        return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
    }
});

很明显上述写法仍然让人觉得繁琐、复杂,进一步可利用Lambda表达式进行化简:

Collections.sort(arr, (Student o1, Student o2) -> {
     
    return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
});

再进行一些化简(去掉参数类型):

Collections.sort(arr, (o1, o2) -> {
     
    return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
});

最终利用方法应用进行化简(同时定义了首选比较量相等时的继续比较依据):

Collections.sort(arr, comparing(Student::getGrade)
			.thenComparing(Student::getName));

若需要逆序:

Collections.sort(arr, comparing(Student::getGrade)
			.reversed()
			.thenComparing(Student::getName));

你可能感兴趣的:(Java,Collection,java,接口)