分享

java中Comparator和Comparable接口区别分析

 邓文博_doc 2016-10-02
/**
*@ author StormMaybin
*@ date 2016-10-01
*/
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

生命不息,奋斗不止!


首先,Comparator和Comparable都是接口,具有共同的功能,对于一个实体类进行排序的功能。

Comparator简介

      强行对某个对象 collection 进行整体排序 的比较函数。可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序。

当且仅当对于一组元素 S 中的每个 e1 和 e2 而言,c.compare(e1, e2)==0 与 e1.equals(e2) 具有相等的布尔值时,Comparator c 强行对 S 进行的排序才叫做与 equals 一致 的排序。

当使用具有与 equals 不一致的强行排序能力的 Comparator 对有序 set(或有序映射)进行排序时,应该小心谨慎。假定一个带显式 Comparator c 的有序 set(或有序映射)与从 set S 中抽取出来的元素(或键)一起使用。如果 c 强行对 S 进行的排序是与 equals 不一致的,那么有序 set(或有序映射)将是行为“怪异的”。尤其是有序 set(或有序映射)将违背根据 equals 所定义的 set(或映射)的常规协定。

例如,假定使用 Comparator c 将满足 (a.equals(b) && c.compare(a, b) != 0) 的两个元素 a 和 b 添加到一个空 TreeSet 中,则第二个 add 操作将返回 true(树 set 的大小将会增加),因为从树 set 的角度来看,a 和 b 是不相等的,即使这与 Set.add 方法的规范相反。

注:通常来说,让 Comparator 也实现 Java.io.Serializable 是一个好主意,因为它们在可序列化的数据结构(像 TreeSet、TreeMap)中可用作排序方法。为了成功地序列化数据结构,Comparator(如果已提供)必须实现 Serializable。

在算术上,定义给定 Comparator c 对给定对象 set S 实施强行排序 的关系式 为:

   {(x, y) such that c.compare(x, y) <= 0}.

此整体排序的商 (quotient) 为:
{(x, y) such that c.compare(x, y) == 0}.
它直接遵循 compare 的协定,商是 S 上的等价关系,强行排序是 S 上的整体排序。当我们说 c 强行对 S 的排序是与 equals 一致 的时,意思是说排序的商是对象的 equals(Object) 方法所定义的等价关系:
{(x, y) such that x.equals(y)}. 此接口是 Java Collections Framework 的成员。

Comparable简介

此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。

实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。

对于类 C 的每一个 e1 和 e2 来说,当且仅当 e1.compareTo(e2) == 0 与 e1.equals(e2) 具有相同的 boolean 值时,类 C 的自然排序才叫做与 equals 一致。注意,null 不是任何类的实例,即使 e.equals(null) 返回 false,e.compareTo(null) 也将抛出 NullPointerException。

建议(虽然不是必需的)最好使自然排序与 equals 一致。这是因为在使用自然排序与 equals 不一致的元素(或键)时,没有显式比较器的有序集合(和有序映射表)行为表现“怪异”。尤其是,这样的有序集合(或有序映射表)违背了根据 equals 方法定义的集合(或映射表)的常规协定。

例如,如果将两个键 a 和 b 添加到没有使用显式比较器的有序集合中,使 (!a.equals(b) && a.compareTo(b) == 0),那么第二个 add 操作将返回 false(有序集合的大小没有增加),因为从有序集合的角度来看,a 和 b 是相等的。

实际上,所有实现 Comparable 的 Java 核心类都具有与 equals 一致的自然排序。java.math.BigDecimal 是个例外,它的自然排序将值相等但精确度不同的 BigDecimal 对象(比如 4.0 和 4.00)视为相等。

从数学上讲,定义给定类 C 上自然排序的关系式 如下:

  {(x, y)|x.compareTo(y) <= 0}。

整体排序的商 是:
{(x, y)|x.compareTo(y) == 0}。
它直接遵循 compareTo 的协定,商是 C 的等价关系,自然排序是 C 的整体排序。当说到类的自然排序与 equals 一致 时,是指自然排序的商是由类的 equals(Object) 方法定义的等价关系。
{(x, y)|x.equals(y)}。

以上文字来自jdk1.6 API。。。

Comparator 定义

package java.util;
public interface Comparator<T>
{
    int compare(T o1, T o2);
    boolean equals(Object obj);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

说明:

  1. 若一个类要实现Comparator接口:它一定要实现compareTo(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。
    为什么可以不实现 equals(Object obj) 函数呢? 因为任何类,默认都是已经实现了equals(Object obj)的。 Java中的一切类都是继承于java.lang.Object,在Object.java中实现了equals(Object obj)函数;所以,其它所有的类也相当于都实现了该函数。

  2. int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。

Comparable 定义

package java.lang;
import java.util.*;
public interface Comparable<T> 
{
    public int compareTo(T o);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

说明

  • 假设我们通过 x.compareTo(y) 来“比较x和y的大小”。若返回“负数”,意味着“x比y小”;返回“零”,意味着“x等于y”;返回“正数”,意味着“x大于y”。

Comparator 和 Comparable 比较

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

代码演示

package com.stormma.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/**
 * <em>测试类</em>
 * @author StormMaybin
 */
public class ComparatorAndComparableDemo 
{

    public static void main(String[] args) 
    {
        //定义一个ArrayList容器
        ArrayList<Person> persons = new ArrayList<Person>();
        String [] names = {"StormMa", "Jack", "Rose", "Mary"};
        int [] ages = {20, 21, 21, 18};
        for (int i = 0; i < 4; i++)
            persons.add(new Person(names[i], ages[i]));

        //排序之前
        System.out.println("排序之前: "+persons);


        //按照Person类中实现Comparable接口的规则排序。这里的规则是按照姓名排序
        Collections.sort(persons);
        System.out.println("按照姓名排序: "+persons);


        //通过AscAgeComparator比较器进行排序,即按照年龄升序排列
        Collections.sort(persons, new AscAgeComparator());
        System.out.println("按照年龄升序排序"+persons);


        //通过DscAgeComparator比较器进行排序,即按照年龄降序排列
        Collections.sort(persons, new DscAgeComparator());
        System.out.println("按照年龄降序排序"+persons);


        //通过AscAgeAscNameComparator比较器进行排序
        //即按照首先按照年龄升序,年龄相同的情况下,
        //按照姓名升序排列
        Collections.sort(persons, new AscAgeAscNameComparator());
        System.out.println("按照年龄和姓名升序排列: "+persons);
    }
}


/**
 * <em>Person类实现Comparable,按姓名升序排列</em>
 * @author StormMaybin
 */
class Person implements Comparable<Person>
{
    private String name;
    private int age;
    //Constructor
    public Person (String name, int age)
    {
        this.name = name;
        this.age = age;
    }
     /**
     * 比较两个Person是否相等:若它们的name和age都相等,则认为它们相等
     */
    boolean equals(Person o) 
    {
        if (this.age == o.age && this.name == o.name)
            return true;
        return false;
    }
    /**
     * 实现Comparable接口,这里只针对姓名进行排序
     */
    @Override
    public int compareTo(Person o) 
    {
        // TODO Auto-generated method stub
        return this.name.compareTo(o.name);
    }
    @Override
    public String toString() 
    {
        // TODO Auto-generated method stub
        return "( name: " + name +","+ "age: "+age+")";
    }
    public int getAge() 
    {
        return age;
    }
    public void setAge(int age)
    {
        this.age = age;
    }
    public String getName() 
    {
        return name;
    }
    public void setName(String name) 
    {
        this.name = name;
    }
}

/**
 * <em>定义AscAgeComparator比较器实现Comparator接口
 * 对Person类的age属性进行升序排列</em>
 * @author StormMaybin
 */
class AscAgeComparator implements Comparator<Person>
{

    @Override
    public int compare(Person o1, Person o2) 
    {
        // TODO Auto-generated method stub
        return o1.getAge() - o2.getAge();
    }
}


/**
 * <em>定义DscAgeComparator比较器实现Comparator接口
 * 对Person类的age属性进行降序排列</em>
 * @author StormMaybin
 */
class DscAgeComparator implements Comparator<Person>
{

    @Override
    public int compare(Person o1, Person o2) 
    {
        // TODO Auto-generated method stub
        return -(o1.getAge() - o2.getAge());
    }
}
/**
 * <em>定义AscAgeAscNameComparator比较器实现Comparator接口
 * 对Person类的age name 属性升序排列</em>
 * @author StormMaybin
 */
class AscAgeAscNameComparator implements Comparator<Person>
{

    @Override
    public int compare(Person o1, Person o2) 
    {
        // TODO Auto-generated method stub
        if (o1.getAge() == o2.getAge())
            return o1.getName().compareTo(o2.getName());
        else
            return o1.getAge() - o2.getAge();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155

测试结果:
这里写图片描述

上述例子足以看出,Comparable是让一个实体类具有排序的能力,而Comparator充当一个比较器的作用,不同实体类排序可以依据同一个比较器。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多