121

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

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

  1. 我做了什么可以接受的做法?

  2. 正确的方法是“首先让类实现 Comparable(用于自然排序),如果需要替代字段比较,则创建一个实现 Comparator 的新类”?

  3. 如果上面的(2)是真的,那么这是否意味着只有在类实现 Comparable 之后才应该实现 Comparator ?(假设我拥有原始课程)。

4

19 回答 19

135

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

如果Comparator你想定义一个外部可控的排序行为,使用它可以覆盖默认的排序行为。

于 2010-02-15T15:17:45.680 回答
84

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

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

换句话说,给定类名,是否清楚可比较的排序方式,还是您必须求助于阅读 javadoc?如果是后者,很可能未来的每个排序用例都需要一个比较器,此时可比较的实现可能会减慢类用户的速度,而不是加快他们的速度。

于 2010-02-15T15:18:21.280 回答
61

使用Comparable

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

使用Comparator

  • 如果对象不在您的控制范围内并且您无法使它们实现Comparable
  • 当您想要比较与默认(由 指定Comparable)行为不同的行为时。
于 2010-02-15T15:21:33.057 回答
26

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

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

  • 能够将当前对象与提供的对象进行比较。
  • 通过使用它,我们可以only one sort sequence基于实例属性来实现。前任:Person.id
  • 一些预定义类如 String、Wrapper 类、Date、Calendar 已经实现了 Comparable 接口。

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

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

  • 能够比较任何两个相同类型的对象。
  • 通过使用它,我们可以many sort sequence根据实例属性来实现和命名每个。前任:Person.id, Person.name, Person.age
  • 我们可以为我们的预定义类实现 Comparator 接口以进行自定义排序。

例子:

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)
    }
}
  • 对于自定义排序,我们使用比较器@compare(o1, o2),对于其他场景,我们使用可比较的@compareTo(o1),如果我们想要对多个字段进行排序,则无需更改代码,然后我们使用比较器。

对于Java 8 Lambda:比较器,请参阅我的帖子。

于 2015-07-06T11:24:03.410 回答
13

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

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

Comparable 由需要为其对象定义自然顺序的类实现。例如,String 实现 Comparable。

如果需要不同的排序顺序,则实现比较器并定义自己的方式来比较两个实例。

于 2011-07-06T08:23:46.933 回答
12

如果对象的排序需要基于自然顺序,则使用 Comparable,而如果需要对不同对象的属性进行排序,则使用 Java 中的 Comparator。

Comparable 和 Comparator 的主要区别:

+------------------------------------------------------------------------------------+
¦               Comparable                ¦                Comparator                ¦
¦-----------------------------------------+------------------------------------------¦
¦ java.lang.Comparable                    ¦ java.util.Comparator                     ¦
¦-----------------------------------------+------------------------------------------¦
¦ int objOne.compareTo(objTwo)            ¦ int compare(objOne, objTwo)              ¦
¦-----------------------------------------+------------------------------------------¦
¦ Negative, if objOne < objTwo            ¦ Same as Comparable                       ¦
¦ Zero,  if objOne == objTwo              ¦                                          ¦
¦ Positive,  if objOne > objTwo           ¦                                          ¦
¦-----------------------------------------+------------------------------------------¦
¦ You must modify the class whose         ¦ You build a class separate from to sort. ¦
¦ instances you want to sort.             ¦ the class whose instances you want       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Only one sort sequence 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, Calendar ¦ instances of third-party classes.        ¦
+------------------------------------------------------------------------------------+
于 2018-05-22T06:21:11.090 回答
10

Comparator 做了所有可比的事情,还有更多。

| | 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

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

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());
        }
    });
}

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

  • 按优先级排序帐户
  • 按类型排序帐户
  • sortAccountsByPriorityAndType

    ETC...

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

于 2014-11-16T08:27:34.267 回答
8

我会说:

  • 如果比较是直观的,那么一定要实现 Comparable
  • 如果不清楚您的比较是否直观,请使用比较器,因为它更明确,因此对于必须维护代码的可怜人来说更清楚
  • 如果可能有多个直观的比较,我更喜欢 Comparator,可能由要比较的类中的工厂方法构建。
  • 如果比较是特殊目的,请使用 Comparator
于 2010-02-15T15:31:03.343 回答
7

以下几点可以帮助您决定在哪些情况下应该使用 Comparable 以及在哪个 Comparator 中使用:

1) 代码可用性

2)单对多排序标准

3) Arays.sort() 和 Collection.sort()

4) 作为 SortedMap 和 SortedSet 中的键

5)更多的类与灵活性

6) 类间比较

7) 自然秩序

有关更详细的文章,您可以参考何时使用可比较以及何时使用比较器

于 2015-07-26T02:41:32.393 回答
5

如果您需要自然顺序排序 - 用户可比较 如果您需要自定义顺序排序 - 使用比较器

例子:

Class Employee{
private int id;
private String name;
private String department;
}

自然顺序排序将基于 id,因为它是唯一的,并且自定义顺序排序将是名称和部门。

参考:
什么时候应该是 Comparable 和/或 Comparator 的类? http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html

于 2011-10-12T10:02:45.317 回答
4
  • 如果在编写课程时您只有一个排序用例,请使用 Comparable。
  • 只有当您有多个排序策略时,才实施比较器。
于 2010-02-15T16:15:31.690 回答
3

这里有一个类似的问题:一个类什么时候应该是 Comparable 和/或 Comparator?

我会说以下内容:为自然排序之类的东西实现 Comparable,例如基于内部 ID

如果您有更复杂的比较算法,例如多个字段等,请实施 Comparator。

于 2010-02-15T15:17:33.433 回答
2

可比性:
每当我们只想存储同质元素并且需要默认的自然排序顺序时,我们可以使用类实现 comparable接口。

Comparator:
当我们想要存储同质和异质元素并且想要按照默认的自定义排序顺序进行排序时,我们可以去comparator接口。

于 2011-12-12T03:18:47.377 回答
0

我的需要是根据日期排序的。

所以,我使用了 Comparable,它对我来说很容易工作。

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

Comparable 的一个限制是它们不能用于列表以外的集合。

于 2012-10-29T08:00:23.770 回答
0

如果您拥有该课程,则最好使用Comparable。通常,如果您不拥有该类,则使用Comparator,但您必须使用TreeSetTreeMap,因为 Comparator 可以作为参数在 TreeSet 或 TreeMap 的构造函数中传递。您可以在http://preciselyconcise.com/java/collections/g_comparator.php中查看如何使用 Comparator 和 Comparable

于 2014-05-20T12:02:43.817 回答
0

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

在对象上实现 Comparable 接口允许隐式排序算法使用覆盖的 compareTo 方法对排序元素进行排序,这将是线性时间。

于 2015-07-15T18:30:35.987 回答
0

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

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

Comparator 是通过覆盖比较方法在自定义 myComparator 类中实现的自定义排序顺序,例如:

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]
于 2018-09-13T16:18:24.950 回答
-1

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

于 2011-10-12T05:58:22.670 回答
-2

我用于实现Comparable和的注释库Comparator

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

于 2012-01-08T01:42:31.077 回答