1

我知道这些接口用于对集合中的对象进行排序。但我怀疑这些的真正区别。我读到的一个事实是,当您想比较两个对象而不是当前对象(this)时使用可比较。

但我的问题是即使使用比较器我们比较相同的对象类型知道。

这里真正的区别是什么。我很困惑。假设以下示例,

class Person implements Comparable<Person> {
  private String firstName;
  private String lastName;
  private int age;

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  public int compareTo(Person anotherPerson){     
    int anotherPersonAge =anotherPerson.getAge();  
    return this.age - anotherPersonAge;    
  }
}

如果我使用比较器,我将有一个类实现比较器,而不是 this.age,它有 person.age。那么这里有什么不同呢?

public class LastNameComparator implements Comparator<Person> {
  public int compare(Person person, Person anotherPerson) {
    int age1 = person.getAge();
    int age2 = anotherPerson.getAge();

     return age1 - age2; 
  }
}

我不知道 Collections.sort 使用的内部逻辑。如果是的话,请证明上述观点是正确的。

我也相信没有必要返回 -1,1 或 0 对。上面的实现也是有效的吧?我遇到的一个问题是,如果我们返回 1,列表如何根据升序或降序对项目进行排序?我认为它的差异考虑并根据差异对其进行排序。

4

5 回答 5

1

考虑两个Comparable的文档

该接口对实现它的每个类的对象进行了总排序。这种排序称为类的自然排序,类的 compareTo 方法称为其自然比较方法。

比较器

一个比较函数,它对某些对象集合进行总排序。比较器可以传递给排序方法(例如 Collections.sort 或 Arrays.sort),以允许精确控制排序顺序。比较器还可用于控制某些数据结构(例如排序集或排序图)的顺序,或为不具有自然排序的对象集合提供排序。

一个Comparable对象可以通过将自己与另一个对象进行比较来确定其顺序(自然排序),而 aComparator是一个知道如何比较两个对象并确定它们的特定顺序的对象。这里的区别在于谁负责比较。

自然排序强加了一个定义的顺序,compareTo但是如果你想改变那个顺序,或者更糟糕的是,没有定义的比较逻辑怎么办?这是Comparator派上用场的地方,因为您可以根据可以通过发出 new 动态切换的不同比较对集合进行排序Comparator,而不是一些讨厌的逻辑,您应该告诉Comparable对象“嘿,现在您根据名称而不是年龄排序”。

关于比较结果之间的差异,对每个对象进行检查。例如,取三个年龄1015和的人2015与 比较时返回 1,10但与 比较-1时返回20,定义三个人的顺序。

选择适合您需求的方法。如果您的比较逻辑是稳定的并且将来不会更改,您可能希望拥有Comparable对象,但如果您需要根据不同的标准对集合进行排序,您应该选择Comparators.

于 2012-12-04T16:50:19.947 回答
0

在 Java 中,一个类型总是只能实现一次接口,也就是说你不能说

public class Foo implements Comparable<Foo>, Comparable<String> {}

这意味着 的实例Foo将始终以某种方式排序 - 您不能让排序在特定上下文中以一种方式运行,而在另一个上下文中以不同方式运行。

Comparator另一方面,它独立于它可以排序的实例。Comparator一个类型可以有尽可能多的 s (而不是只有一个Comparable)。如果您需要某种排序,只需创建一个新的即可Comparator

Comparator编写一个对不同类型的实例进行分类的实例也很容易——这很难做到,Comparable因为所有涉及的实例都必须相互了解:任何实例都可以获取任何其他实例作为参数,compareTo()并且它们必须实现一些通用接口, ETC。

于 2012-12-04T17:04:15.370 回答
0

对 java.util.Collections javadocs 的快速浏览提供了以下信息:

public static void sort(List list) - 根据其元素的自然顺序将指定列表按升序排序。列表中的所有元素都必须实现 Comparable 接口。此外,列表中的所有元素必须相互可比较(即,e1.compareTo(e2) 不得为列表中的任何元素 e1 和 e2 抛出 ClassCastException)。

public static void sort(List list, Comparator c) - 根据指定比较器的顺序对指定列表进行排序。列表中的所有元素必须使用指定的比较器进行相互比较(即,c.compare(e1, e2) 不得为列表中的任何元素 e1 和 e2 抛出 ClassCastException)。

可以推断,sort(List list)然后使用Comparable接口并sort(List list, Comparator c)使用比较器。

要回答您的最后一个问题,以您描述的方式使用这两种方法没有区别......使用这两种方法的目的是让您可以以不同的方式比较对象,而不是使用不同的实现以相同的方式比较对象。

于 2012-12-04T16:53:07.217 回答
0

当有些人使用 Comparable 接口时,我总是感到害怕,因为它几乎总是错误的选择。Comparable 用于定义自然顺序,而不是用于排序。Java 知道必须履行的 equals-hashcode 契约。大多数开发人员都知道。但是还有一个重要的合同:平等可比合同。

这意味着:

a.equals(b) <==> a.compareTo(b) == 0

在您的示例中,一个 TreeSet 中不能有两个年龄相同的不同人。

于 2014-05-06T20:43:36.757 回答
0

以这种方式考虑...您有一个具有一个整数的IntegerWrapper类,并且您在该类中实现了Comparable 。因此,当使用 Collection.sort 对这些进行排序时...它将按升序为您提供对象...

但是当您想更改此顺序并希望降序时,您必须实现比较器以按所需顺序对它们进行排序......

于 2012-12-04T16:58:05.367 回答