关于java:何时使用Comparable和Comparator

When to use Comparable and Comparator

我有一个需要在一个字段上排序的对象列表,比如score。我没有多想,而是编写了一个实现Comparator的新类,它完成了任务,并且工作正常。

现在回顾一下,我想知道我是否应该让我的类实现具有可比性,而不是创建一个实现Comparator的新类。分数是排序对象的唯一字段。

  • 我所做的作为实践是可以接受的?

  • 正确的方法是"首先让类实现具有可比性(对于自然排序),如果需要进行可选的字段比较,那么创建一个实现比较器的新类"?

  • 如果上面的(2)是真的,那么这是否意味着只有在类实现具有可比性之后才应该实现Comparator?(假设我拥有原来的班级)。


  • 使用Comparable。如果要定义相关对象的默认(自然)排序行为,通常的做法是使用技术或自然(数据库?)此对象的标识符。

    使用Comparator如果要定义外部可控制的排序行为,可以覆盖默认的排序行为。


    我会说,如果这是对类进行排序的自然方法,那么对象应该实现Comparable,并且任何人都需要对类进行排序,通常都希望这样做。

    但是,如果排序是类的一种不寻常的用法,或者排序只对特定的用例有意义,那么比较器是更好的选择。

    换一种方式,考虑到类名,是否很清楚比较类的排序方式,或者您必须阅读javadoc?如果是后者,那么每一个未来的排序用例都可能需要一个比较器,此时,Comparable的实现可能会减慢类用户的速度,而不是加快他们的速度。


    使用Comparable

    • 如果对象在您的控制范围内。
    • 如果比较行为是主要的比较行为。

    使用Comparator

    • 如果对象在您的控制范围之外,并且您不能使它们实现Comparable
    • 当您想要比较不同于默认(由Comparable行为指定)的行为时。

    可比-java.lang.Comparable: int compareTo(Object o1)

    可比对象能够将自身与另一个对象进行比较。类本身必须实现java.lang.Comparable接口,以便能够比较其实例。

    • 能够将当前对象与提供的对象进行比较。
    • 通过使用它,我们可以基于实例属性实现only one sort sequence。例:Person.id
    • 一些预定义的类(如字符串、包装类、日期、日历)实现了类似的接口。

    比较器-java.util.Comparator: int compare(Object o1, Object o2)

    比较器对象能够比较两个不同的对象。该类不比较其实例,而是比较其他一些类的实例。这个comparator类必须实现java.util.comparator接口。

    • 能够比较同一类型的任何两个对象。
    • 通过使用它,我们可以实现many sort sequence,并根据实例属性分别命名。例:Person.id, Person.name, Person.age
    • 我们可以实现比较器接口到预先定义的类,以便进行定制排序。

    例子:

    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
    public class Employee implements Comparable<Employee> {

        private int id;
        private String name;
        private int age;
        private long salary;

        // Many sort sequences can be created with different names.
        public static Comparator<Employee> NameComparator = new Comparator<Employee>() {        
            @Override
            public int compare(Employee e1, Employee e2) {
                return e1.getName().compareTo(e2.getName());
            }
        };
        public static Comparator<Employee> idComparator = new Comparator<Employee>() {      
            @Override
            public int compare(Employee e1, Employee e2) {
                return Integer.valueOf(e1.getId()).compareTo(Integer.valueOf(e2.getId()));
            }
        };

        public Employee() { }
        public Employee(int id, String name, int age, long salary){
            this.id = id;
            this.name = name;
            this.age = age;
            this.salary = salary;
        }
        // setters and getters.

        // Only one sort sequence can be created with in the class.
        @Override
        public int compareTo(Employee e) {
        //return Integer.valueOf(this.id).compareTo(Integer.valueOf(e.id));
        //return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
            if (this.id > e.id) {
                return 1;
            }else if(this.id < e.id){
                return -1;
            }else {
                return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
            }

        }  

        public static void main(String[] args) {

            Employee e1 = new Employee(5,"Yash", 22, 1000);
            Employee e2 = new Employee(8,"Tharun", 24, 25000);

            List<Employee> list = new ArrayList<Employee>();
            list.add(e1);
            list.add(e2);
            Collections.sort(list); // call @compareTo(o1)
            Collections.sort(list, Employee.nameComparator); // call @compare (o1,o2)
            Collections.sort(list, Employee.idComparator); // call @compare (o1,o2)
        }
    }
    • 对于定制排序,我们选择comparator@compare(o1,o2)作为其他场景,我们选择comparable@compare to(o1),如果我们想对多个字段排序,则使用comparator。

    对于Java 8 lambda:比较器参考我的帖子。


    比较器做所有可比的事情,加上更多。

    | | Comparable | Comparator
    ._______________________________________________________________________________
    Is used to allow Collections.sort to work | yes | yes
    Can compare multiple fields | yes | yes
    Lives inside the class you’re comparing and serves | |
    as a"default" way to compare | yes | yes
    Can live outside the class you’re comparing | no | yes
    Can have multiple instances with different method names | no | yes
    Input arguments can be a list of | just Object| Any type
    Can use enums | no | yes

    我发现使用比较器作为匿名类的最佳方法如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    private static void sortAccountsByPriority(List<AccountRecord> accounts) {
        Collections.sort(accounts, new Comparator<AccountRecord>() {

            @Override
            public int compare(AccountRecord a1, AccountRecord a2) {
                return a1.getRank().compareTo(a2.getRank());
            }
        });
    }

    您可以在计划排序的类内创建此类方法的多个版本。所以你可以有:

    • 分类科目分类
    • 分类科目分类
    • 排序科目按优先级和类型

      等...

    现在,您可以在任何地方使用这些排序方法并获得代码重用。这给了我一个可比的一切,再加上更多…所以我看不出有任何理由使用可比性。


    比较同一类的实例时应使用Comparable。

    比较器可以用来比较不同类的实例。

    Comparable由需要为其对象定义自然顺序的类实现。类似于字符串的实现是可比较的。

    如果一个人想要一个不同的排序顺序,那么他可以实现比较器并定义自己的方式来比较两个实例。


    我会说:

    • 如果比较是直观的,那么无论如何都要实现可比较的
    • 如果还不清楚你的比较是否直观,那就用比较器,因为它更直观。对于必须维护代码的可怜灵魂来说,更明确,也更清楚。
    • 如果有不止一个直观的比较可能,我更喜欢比较器,可能是由要比较的类中的工厂方法生成的。
    • 如果比较是特殊目的,使用比较器

    如果对象的排序需要基于自然顺序,则使用可比性,而如果需要对不同对象的属性进行排序,那么在Java中使用比较器。

    可比性与比较器的主要区别:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    +------------------------------------------------------------------------------------+
    |               Comparable                |                Comparator                |
    |-----------------------------------------+------------------------------------------|
    | java.lang.Comparable                    | java.util.Comparator                     |
    |-----------------------------------------+------------------------------------------|
    | int objOne.compareTo(objTwo)            | int compareTo(objOne, objTwo)            |
    |-----------------------------------------+------------------------------------------|
    | Negative, if objOne < objTwo            | Same as Comparable                       |
    | Zero,  if objOne == objTwo              |                                          |
    | Positive,  if objOne > objTwo           |                                          |
    |-----------------------------------------+------------------------------------------|
    | You must modify the clas whose          | You build a class separate from to sort. |
    | instances you want to sort.             | the class whose instances you want       |
    |-----------------------------------------+------------------------------------------|
    | Only one sort sequemce can be created   | Many sort sequences can be created       |
    |-----------------------------------------+------------------------------------------|
    | Implemented frequently in the API by:   | Meant to be implemented to sort          |
    | String, Wrapper classes, Date, Calandar | instances of third-party classes.        |
    +------------------------------------------------------------------------------------+

    以下几点有助于您决定在哪些情况下应该使用比较工具以及在哪些情况下使用比较工具:

    1)代码可用性

    2)单个与多个排序标准

    3)arays.sort()和collection.sort()。

    4)作为sortedmap和sortedset中的键

    5)更多的类与灵活性

    6)类别间比较

    7)自然秩序

    有关更详细的文章,您可以参考何时使用Comparable和何时使用Comparator。


    • 如果在上课的时候您只有一个排序用例使用可比性。
    • 只有当你有一个以上排序策略实现比较器。

    如果您需要自然排序——用户可比如果您需要定制的订单排序-使用比较器

    例子:

    1
    2
    3
    4
    5
    Class Employee{
    private int id;
    private String name;
    private String department;
    }

    自然排序将基于ID,因为它是唯一的,自定义排序在G中是名称和部门。

    折射率:什么时候应该比较类和/或比较类?http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html


    这里有一个类似的问题:什么时候一个类应该具有可比性和/或比较性?

    我想说的是:实现类似于自然顺序的类似功能,例如基于内部ID

    如果您有一个更复杂的比较算法(例如多个字段等),请实现一个比较器。


    可比的:只要我们只想存储同构元素和所需的默认自然排序顺序,我们就可以使用实现Comparable接口的类。

    Comparator:每当我们想要存储同质和异类元素,并且我们想要按照默认的定制排序顺序排序时,我们可以使用Comparator接口。


    Comparable是为数字值提供的默认自然排序顺序为升序,字符串为字母顺序。例如:

    1
    2
    3
    4
    Treeset t=new Treeset();
    t.add(2);
    t.add(1);
    System.out.println(t);//[1,2]

    Comparator是通过重写Compare方法在自定义MyComparator类中实现的自定义排序顺序。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    Treeset t=new Treeset(new myComparator());
    t.add(55);
    t.add(56);
    class myComparator implements Comparator{
    public int compare(Object o1,Object o2){
    //Descending Logic
    }
    }
    System.out.println(t);//[56,55]

    我的需要是按日期排序的。

    所以,我用了可比的,它很容易为我工作。

    1
    2
    3
    4
    public int compareTo(GoogleCalendarBean o) {
        // TODO Auto-generated method stub
        return eventdate.compareTo(o.getEventdate());
    }

    具有可比性的一个限制是,它们不能用于列表以外的集合。


    如果你拥有这门课,最好跟比较级的去。通常,如果您不拥有类,但必须使用TreeSet或TreeMap,则使用Comparator,因为Comparator可以作为TreeSet或TreeMap的contructor中的参数传递。您可以在http://preciselyconcise.com/java/collections/g_comparator.php中看到如何使用comparator和comparable。


    在一次采访中,我被要求在比非登录时间更好的时间内对一定范围的数字进行排序。(不使用计数排序)

    在对象上实现可比较的接口允许隐式排序算法使用重写的CompareTo方法对元素排序,这将是线性时间。


    非常简单的方法是假设所讨论的实体类在数据库中表示,然后在数据库表中,您是否需要由实体类字段组成的索引?如果答案是"是",则实现Comparable并使用索引字段进行自然排序。在所有其他情况下,使用比较器。


    用于实现ComparableComparator的注释库:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Person implements Comparable<Person> {        
        private String firstName;  
        private String lastName;        
        private int age;        
        private char gentle;        

        @Override        
        @CompaProperties({ @CompaProperty(property ="lastName"),              
            @CompaProperty(property ="age",  order = Order.DSC) })          
        public int compareTo(Person person) {                
            return Compamatic.doComparasion(this, person);        
        }  
    }

    单击链接查看更多示例。http://code.google.com/p/compamatic/wiki/compamaticbyexamples网站