Java Comparable 和 Comparator

Comparable 和 Comparator 接口都是用来比较大小的,首先来看一下 Comparable 的定义:

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

Comparator的定义如下:

package java.util;
public interface Comparator<T> {
    int compare(T o1, T o2);
}

Comparable对实现它的每个类的对象进行整体排序。这个接口需要类本身去实现。若一个类实现了Comparable 接口,实现 Comparable 接口的类的对象的 List 列表 ( 或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。

举例(类Person1实现了Comparable接口)

public class Person1 implements Comparable<Person1> {
    private int age;
    private String name;

    public Person1(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public int compareTo(Person1 o) {
        return this.age - o.age;
    }
    @Override 
    public String toString() {
        return name+":"+age;
    }
}

可以看到 Person1 实现了 Comparable 接口中的 compareTo 方法。实现Comparable 接口必须修改自身的类,即在自身类中实现接口中相应的方法。

而 compareTo(Person1 o) 的返回值 是 this.age - o.age 的结果,决定了最后的排序结果是 升序(从左到右的方向上,数据从小到大) 还是 降序(从左到右的方向上,数据从大到小)。

compareTo 方法中的参数:Person1 o 表示被比较的对象,而 Person1 自身的类 是主动比较的对象。

通俗的讲,就是 “我” 要和 “谁” 比较,this.age表示“我”,o.age表示“谁”,即被比较的对象;
如果返回值 是 正数,即 this.age 大于 o.age,则让 this.age 即“我”排在后面,“o.age” 即 被比较的对象 排在前面,从排序结果来看 就是 升序;
如果返回值 是 负数,即 this.age 小于 o.age,则让 this.age 即“我”排在前面,“o.age” 即 被比较的对象 排在后面,从排序结果来看 还是 升序;

一句话总结:
如果返回值为正,则把主动比较的值放后面;
如果返回值为负,则把主动比较的值放前面。

通过上面的总结,如果想让排序的结果表现为 降序,则要把 compareTo 方法中的代码改为:return o.age - this.age,再简单分析下:如果 o.age 大于 this.age,则返回值为正,要把主动比较的值 this.age 放在后面,this.age 是较小的值,而它放在了后面,最终的排序结果即是 降序;反之 o.age 小于 this.age,返回值为负,this.age 放前面,this.age 较大且放在前面,最终结果还是降序。

(貌似讲 返回值决定顺序的 ,笔者讲的是全网最详细的了有木有?还有谁!)

测试代码:

Person1 person1 = new Person1("zzh",18);
Person1 person2 = new Person1("jj",17);
Person1 person3 = new Person1("qq",19);

List<Person1> list = new ArrayList<>();
list.add(person1);
list.add(person2);
list.add(person3);

System.out.println(list);
Collections.sort(list);
System.out.println(list);

输出结果:

[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19]

如果我们的这个类无法修改,这就用到了Comparator这个接口:

public final class Person2 {
    private int age;
    private String name;

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

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

如类Person2,这个类已经固定,无法进行对其类自身的修改,也修饰词final了,你也别想 implements Comparable,那么此时怎么办呢?在类的外部使用 Comparator的接口。如下测试代码:

Person2 p1 = new Person2("zzh",18);
Person2 p2 = new Person2("jj",17);
Person2 p3 = new Person2("qq",19);

List<Person2> list2 = new ArrayList<Person2>();
list2.add(p1);
list2.add(p2);
list2.add(p3);

System.out.println(list2);

Collections.sort(list2,new Comparator<Person2>() {
    @Override
    public int compare(Person2 o1, Person2 o2) {
        return o1.getAge() - o2.getAge();
    }
});

System.out.println(list2);

输出结果:

[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19] 

上面讲到 Comparable 的 compareTo 方法的返回值 决定排序结果,而 Comparator 是根据 compare 方法的返回值 决定排序结果。它们俩的排序逻辑是一样一样滴~。compare 方法中的参数,第一个参数 是主动比较的值,第二个参数 是被比较的值。

总结

Comparable 是排序接口;若一个类实现了 Comparable 接口,就意味着 “该类支持排序”。而 Comparator 是比较器;我们若需要控制某个类的次序,可以建立一个 “该类的比较器” 来进行排序。

前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。可以说前者属于 “静态绑定”,而后者可以 “动态绑定”。

我们不难发现:Comparable 相当于 “内部比较器”,而 Comparator 相当于 “外部比较器”。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容