为什么Java类应实现可比性?


Answers:


212

这是真实的示例。请注意,它String也实现Comparable

class Author implements Comparable<Author>{
    String firstName;
    String lastName;

    @Override
    public int compareTo(Author other){
        // compareTo should return < 0 if this is supposed to be
        // less than other, > 0 if this is supposed to be greater than 
        // other and 0 if they are supposed to be equal
        int last = this.lastName.compareTo(other.lastName);
        return last == 0 ? this.firstName.compareTo(other.firstName) : last;
    }
}

后来..

/**
 * List the authors. Sort them by name so it will look good.
 */
public List<Author> listAuthors(){
    List<Author> authors = readAuthorsFromFileOrSomething();
    Collections.sort(authors);
    return authors;
}

/**
 * List unique authors. Sort them by name so it will look good.
 */
public SortedSet<Author> listUniqueAuthors(){
    List<Author> authors = readAuthorsFromFileOrSomething();
    return new TreeSet<Author>(authors);
}

15
我只想指出,通常您需要覆盖equals(因此hashCode)以与您的compareTo方法保持一致。例如,如果您想让班级与一起玩,这是必要的TreeSet
pidge 2012年

为什么不简单地返回last
Anirban Nag'tintinmj',2015年

@ AnirbanNag'tintinmj'在姓氏相同的情况下按名字自动排序。
OddDev

再加上一个很好的解释,为什么compareTo返回一个int及其含义。最有帮助。
james.garriss

1
@ user3932000:是的,这几乎是所有接口的重点。但是请注意,“其他Java方法”包括用户编写的方法!实际上,我声称大多数接口都被用户的代码占用。在较大的代码库中,“您自己”迅速变为“其他”
Enno Shioji

40

可比定义自然排序。这意味着您在定义一个对象应被视为“小于”或“大于”时进行定义。

假设您有一堆整数,并且想要对它们进行排序。这很简单,只需将它们放入已排序的集合中,对吗?

TreeSet<Integer> m = new TreeSet<Integer>(); 
m.add(1);
m.add(3);
m.add(2);
for (Integer i : m)
... // values will be sorted

但是现在假设我有一些自定义对象,排序对我来说很有意义,但未定义。假设,我有按邮政编码和人口密度表示地区的数据,我想按密度对它们进行排序:

public class District {
  String zipcode; 
  Double populationDensity;
}

现在,对它们进行排序的最简单方法是通过实现Comparable以自然的顺序定义它们,这意味着有一种标准的方式将这些对象定义为有序的:

public class District implements Comparable<District>{
  String zipcode; 
  Double populationDensity;
  public int compareTo(District other)
  {
    return populationDensity.compareTo(other.populationDensity);
  }
}

请注意,您可以通过定义比较器来做等效的事情。不同之处在于,比较器在对象外部定义了排序逻辑。也许在一个单独的过程中,我需要通过邮政编码对相同的对象进行排序-在这种情况下,排序不一定是对象的属性,或者不同于对象的自然排序。您可以使用外部比较器来定义整数的自定义顺序,例如通过按字母顺序对它们进行排序。

基本上,排序逻辑必须存在于某个地方。可以是-

  • 在对象本身中,如果它是自然可比较的(扩展Comparable -eg整数)

  • 如上例所示,由外部比较器提供。


很好的例子,但是必须TreeSet<Integer>代替TreeMap<Integer>,因为后者不存在,TreeMap总是-pairs <Key,Value>。顺便说一句,假想的TreeMap<District, Object>只有在地区实施可比性的情况下才行,对吧?仍然试图理解这一点
phil294

14

引用javadoc;

此接口对实现该接口的每个类的对象强加了总体排序。此排序称为类的自然排序,而该类的compareTo方法被称为其自然比较方法。

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

编辑:..并使重要的部分加粗。


4
我想说的是,您加粗的那句话后面的句子同样重要(如果不是更多的话)。
Michael Borgwardt 2010年

8

类实现的事实Comparable意味着您可以从该类中获取两个对象并进行比较。某些类,例如某些集合(集合中的排序函数),可以使对象保持顺序以使其具有可比性(为了进行排序,您需要知道哪个对象是“最大”对象,依此类推)。


8

上面的大多数示例都显示了如何在compareTo函数中重用现有的可比较对象。如果要比较同一个类的两个对象时想实现自己的compareTo,请说一个AirlineTicket对象,该对象要按价格排序(少排在首位),然后是中途停留的次数(再说一次,少是位居第一),您可以执行以下操作:

class AirlineTicket implements Comparable<Cost>
{
    public double cost;
    public int stopovers;
    public AirlineTicket(double cost, int stopovers)
    {
        this.cost = cost; this.stopovers = stopovers ;
    }

    public int compareTo(Cost o)
    {
        if(this.cost != o.cost)
          return Double.compare(this.cost, o.cost); //sorting in ascending order. 
        if(this.stopovers != o.stopovers)
          return this.stopovers - o.stopovers; //again, ascending but swap the two if you want descending
        return 0;            
    }
}

6

一种实现多字段比较的简单方法是使用Guava的ComparisonChain-然后您可以说

   public int compareTo(Foo that) {
     return ComparisonChain.start()
         .compare(lastName, that.lastName)
         .compare(firstName, that.firstName)
         .compare(zipCode, that.zipCode)
         .result();
   }

代替

  public int compareTo(Person other) {
    int cmp = lastName.compareTo(other.lastName);
    if (cmp != 0) {
      return cmp;
    }
    cmp = firstName.compareTo(other.firstName);
    if (cmp != 0) {
      return cmp;
    }
    return Integer.compare(zipCode, other.zipCode);
  }
}


2

可比较用于比较您的类的实例。我们可以通过多种方式比较实例,这就是为什么我们需要实现一个方法compareTo以便知道我们如何(比较)比较实例的原因。

Dog 类:

package test;
import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Dog d1 = new Dog("brutus");
        Dog d2 = new Dog("medor");
        Dog d3 = new Dog("ara");
        Dog[] dogs = new Dog[3];
        dogs[0] = d1;
        dogs[1] = d2;
        dogs[2] = d3;

        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * brutus
         * medor
         * ara
         */

        Arrays.sort(dogs, Dog.NameComparator);
        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * ara
         * medor
         * brutus
         */

    }
}

Main 类:

package test;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Dog d1 = new Dog("brutus");
        Dog d2 = new Dog("medor");
        Dog d3 = new Dog("ara");
        Dog[] dogs = new Dog[3];
        dogs[0] = d1;
        dogs[1] = d2;
        dogs[2] = d3;

        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * brutus
         * medor
         * ara
         */

        Arrays.sort(dogs, Dog.NameComparator);
        for (int i = 0; i < 3; i++) {
            System.out.println(dogs[i].getName());
        }
        /**
         * Output:
         * ara
         * medor
         * brutus
         */

    }
}

这是一个很好的示例,说明如何在Java中使用可比性:

http://www.onjava.com/pub/a/onjava/2003/03/12/java_comp.html?page=2


2

实现Comparable接口时,需要实现method compareTo()。您需要使用它来比较对象,以便使用例如ArrayList类的排序方法。您需要一种比较对象以对其进行排序的方法。因此,您需要compareTo()在类中使用自定义方法,以便可以将其与ArrayListsort方法一起使用。该compareTo()方法返回-1,0,1。

我刚刚阅读了Java Head 2.0中的相应章节,但仍在学习中。


1

可以,但是为什么不定义一个compareTo()方法而不实现可比较的接口。例如,Citynametemperature和定义的类

public int compareTo(City theOther)
{
    if (this.temperature < theOther.temperature)
        return -1;
    else if (this.temperature > theOther.temperature)
        return 1;
    else
        return 0;
}

这是行不通的。如果没有实现媲美-我得到classcast例外
卡兰的Ahuja
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.