何时使用Comparable和Comparator

我有一个列表,我需要在字段上sorting,比如Score。 没有太多的想法,我写了一个实现比较器的新类,它完成任务并且工作。

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

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

  2. 是正确的方法“首先有类实现Comparable(对于自然顺序),如果需要替代字段比较,然后创build一个新的类,实现Comparator”?

  3. 如果(2)是真的,那么是否意味着只有在类实现Comparable后才能实现Comparator? (假设我拥有原始类)。

如果这是对类进行sorting的明确的自然方法,那么我会说一个对象应该实现Comparable,而任何需要对类进行sorting的人通常都希望这样做。

但是,如果sorting是class级的不寻常使用,或者sorting只对特定用例有意义,那么比较器是更好的select。

换一种说法,给定类名,是否可以比较类似的问题,还是必须诉诸阅读javadoc呢? 如果是后者,则每个分类用例都需要一个比较器,在这一点上,可比较的实现可能会降低该类用户的速度,而不能加速他们的速度。

如果要定义有问题的对象的默认 (自然)sorting行为,则使用Comparable ,通常的做法是使用该对象的技术或自然(数据库?)标识符。

如果要定义外部可控sorting行为,请使用Comparator ,这可以覆盖默认sorting行为。

使用Comparable

  • 如果对象在你的控制之下。
  • 如果比较行为是主要的比较行为。

使用Comparator

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

当你比较同一类的实例时,应该使用Comparable。

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

Comparable是由需要为其对象定义自然sorting的类实现的。 像String实现Comparable。

如果需要不同的sorting顺序,那么他可以实现比较器并定义自己的比较两个实例的方法。

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

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

您可以在您计划sorting的课程内部创build多个此类方法的版本。 所以你可以有:

  • sortAccountsByPriority
  • sortAccountsByType
  • sortAccountsByPriorityAndType

    等等…

现在,您可以在任何地方使用这些sorting方法并获得代码重用。 这给了我一切可比的,再加上…所以我没有看到任何理由使用可比。

我会说:

  • 如果比较直观,那么一定要用Comparable
  • 如果你不清楚你的比较是否直观,那么使用一个比较器,因为它比较明确,因此对于需要维护代码的可怜的灵魂
  • 如果有多个直观的比较可能,我更喜欢一个比较器,可能由类中的工厂方法build立比较。
  • 如果比较是特殊用途,则使用比较器

Comparablejava.lang.Comparable: int compareTo(Object o1)

一个可比较的对象是能够比较自己与另一个对象。 类本身必须实现java.lang.Comparable接口,以便能够比较它的实例。

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

Comparatorjava.util.Comparator: int compare(Object o1, Object o2)

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

  • 能够比较任何两个相同types的对象。
  • 通过使用这个,我们可以根据实例属性实现many sort sequence和名称。 EX: Person.id, Person.name, Person.age
  • 我们可以为我们的预定义的类实现定制sorting的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) } } 
  • 对于自定义的sorting,我们去为比较@compare(o1,o2)为其他场景我们去比较@compareTo(o1),如果我们想要sorting多个字段,然后我们使用比较器不改变的代码。

对于Java 8 Lambda:Comparator请参考我的文章。

  • 如果在编写这个类的时候,你只有一个用例,使用Comparable。
  • 只有当你有不止一种分拣策略时才使用比较器。

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

我会说以下内容:实现类似自然顺序的东西比如,基于内部ID

如果你有一个比较复杂的比较algorithm,例如多个字段等等,就实现一个比较器。

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

例:

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

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

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

可比:
每当我们只想存储同质元素和默认的自然sorting顺序时,我们可以去实现comparable接口的类。

比较:
无论何时我们想要存储同类和异类元素,并且想要按默认的自定义sorting顺序sorting,我们可以去comparator接口。

以下几点帮助您决定在哪种情况下应该使用Comparable,以及比较器:

1)代码可用性

2)单一与多个sorting标准

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

4)作为SortedMap和SortedSet中的键

5)更多类别与灵活性

6)组间比较

7)自然秩序

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

非常简单的方法是假定所涉及的实体类在数据库中表示,然后在数据库表中需要由实体类的字段组成的索引? 如果答案是肯定的,则实施可比较的操作,并使用索引字段作为自然sorting顺序。 在所有其他情况下使用比较器。

我的需要是根据datesorting的。

所以,我使用了Comparable,它对我来说很简单。

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

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

如果你拥有这个类,那么用Comparable吧 。 如果你不拥有这个类,但是你必须使用TreeSetTreeMap,通常会使用Comparator,因为Comparator可以作为TreeSet或TreeMap的构造函数中的parameter passing。 您可以在http://preciselyconcise.com/java/collections/g_comparator.php中看到如何使用Comparator和Comparable

我曾经被要求在一次面试中sorting一定范围内的数字,比nlogn时间好。 (不使用计数sorting)

在对象上实现Comparable接口允许隐式sortingalgorithm使用重写的compareTo方法来sortingsorting元素,这将是线性时间。

用于实现ComparableComparator注释库:

 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