Comparable与Comparator

Lou.Chen
大约 4 分钟

Comparable与Comparator

中文,字母,数字的比较:

①字符串字母比较:

"ba">"ab" (英文按照ASCII码比较),因为‘a’的是ASCII码是97,而‘b’的是98。

“ba”.compareTo("ab")。 返回1。“ca”.compareTo("ab"),就返回2。

②数字比较:

3.compateTo(5),返回 -1; 5.compateTo(3),返回1; 相等返回0

//Integer中实现的compartTo方法
public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

③中文比较:

中文是按照Unicode编码比较的。 eg: "空".compareTo("冰"),会返回10442。其中“空”的Uiicode的编码为\u7a7a,“冰”的Uiicode的编码为\u51b0,

它们是16进制的。也就是0x7a7a-0x51b0,在转换为十进制就是10442。

综合上述CompareTo方法:

public int compareTo(T o);
e1.compareTo(e2) > 0 即 e1 > e2
e1.compareTo(e2) = 0 即 e1 = e2
e1.compareTo(e2) < 0 即 e1 < e2

这里:调用对象总是减去传入的对象转换为ASCll进行相减。

**String中compareTo实现:**即String默认是从小到大排序

public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

**Integer中compareTo实现:**即Integer默认是从小到大排序

public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
1、Comparable

Compareable更像是**自然排序,**使用一个类继承自Compareable接口,并实现其中compareTo的方法

public class Student implements Comparable<Student>{

    public String name;
    public Integer age;

    public Student() {
    }

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    //getter
    //setter
    //toString
    
    //按照姓名从小到大排序
    //@Override
    //public int compareTo(Student o) {
    //    return name.compareTo(o.name);
    //}
    
    //按照姓名从大到下排序
    //@Override
    //public int compareTo(Student o) {
    //    return o.name.compareTo(name);
    //}
    
    //按照姓名从小到大排序,姓名相同的按照年龄从大到小排序
    @Override
    public int compareTo(Student o) {
        //姓名相同
        if (name.equals(o.name)) {
            //按照age从大到小排序
            return o.age.compareTo(age);
        }else{
            //姓名不相同
            //按照姓名从小到大排序
            return name.compareTo(o.name);
        }
    }
}
public static void main(String[] args) {
        List<Student> list = Arrays.asList(
                new Student("lc", 10),
                new Student("lc", 9),
                new Student("lc", 11),
                new Student("zs", 8),
                new Student("ls", 25),
                new Student("ww", 19),
                new Student("zl", 20)
        );
        System.out.println("排序之前:"+list);
        Collections.sort(list);
        System.out.println("排序之后:"+list);
}
排序之前:[
    {name='lc', age=10}, 
    {name='lc', age=9}, 
    {name='lc', age=11}, 
    {name='zs', age=8}, 
    {name='ls', age=25}, 
    {name='ww', age=19}, 
    {name='zl', age=20}]
排序之后:[
    {name='lc', age=11}, 
    {name='lc', age=10}, 
    {name='lc', age=9}, 
    {name='ls', age=25}, 
    {name='ww', age=19}, 
    {name='zl', age=20}, 
    {name='zs', age=8}]

先按照姓名从小到大排序,如果姓名相同则按照年龄从大到小排序

使用Collection.sort()方法时:

public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
}

必须传入一个实现Comparable或实现comparator接口的类。默认使用的是重写compareTo()的类中的方法

2、Comparator

Comparator更像是定制排序. 当我们的接口没有实现Comparable接口时,我们可以在调用Collections.sort定制其接口

public class Teacher {

    public String name;
    public Integer age;

    public Teacher() {
    }
    public Teacher(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    //getter
    //setter
    //toString
}
public static void main(String[] args) {
        List<Teacher> list = Arrays.asList(
                new Teacher("lc", 10),
                new Teacher("lc", 9),
                new Teacher("lc", 11),
                new Teacher("zs", 8),
                new Teacher("ls", 25),
                new Teacher("ww", 19),
                new Teacher("zl", 20)
        );
        System.out.println("排序之前:"+list);
        Collections.sort(list, new Comparator<Teacher>() {
            @Override
            public int compare(Teacher o1, Teacher o2) {
                //如果姓名相同
                if (o1.name.equals(o2.name)) {
                    //按照年龄小到大排序
                    return o1.age.compareTo(o2.age);
                }else{
                    //姓名不相同,按照姓名从大到小排序
                    return o2.name.compareTo(o1.name);
                }
            }
        });
        System.out.println("排序之后:"+list);
}

按照姓名从大到小排序,如果姓名相同,则按照年龄从小到大排序

当我们定制其接口时,使用collection.sort()

public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
}

第一个参数为比较的集合,第二参数为传入的自定义比较器

3、使用场景比较

注意:Comparator定制的排序规则高于comparable自然排序的规则

实现Comparable接口的方式比实现Comparator接口的耦合性要强一些,如果要修改比较算法,要修改Comparable接口的实现类,而实现Comparator的类是在外部进行比较的,不需要对实现类有任何修改。