一个类何时应该是可比较的和/或可比较的?


138

我看到了同时实现ComparableComparator的类。这是什么意思?为什么我要使用一个?


18
您阅读过有关它们的Javadoc吗?它非常清楚地描述了不同之处。
skaffman

1
什么是可比和比较器,何时使用可比和比较器。要了解这些内容,请阅读此链接。这将帮助您了解其行为和用法。http://iandjava.blogspot.in/2012/10/comparable-and-comparator.html
RockStar 2012年

6
这是一个很好的问题,有一个很好的客观答案。我很沮丧它关闭了。
罗素·席尔瓦

3
关于StackOverflow的其他问题将其称为“比较器和可比较器之间的区别是什么”问题。为什么将其标记为“非建设性的”?作为Java新手,这是一个非常有用的问题!
皮特2014年

Answers:


241

下面的文字来自Comparator vs Comparable

可比

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

比较器

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


有关比较器和比较器的用法的详细说明:sysdotoutdotprint.com/index.php/2017/03/28/…–
mel3kings


@ mel3kings-链接不再可用。
加拉夫

152

实现的Comparable意思是“ 我可以将自己与另一个对象进行比较。 ”当存在单个自然默认比较时,这通常很有用。

实现的Comparator意思是“ 我可以比较两个其他对象。 ”当有多种方式比较一个类型的两个实例时,这通常很有用-例如,您可以按年龄,姓名等比较人员。


1
skeet,您好,请您使用比较器和比较器删除代码。
Mdhar9e 2012年

5
@ mdhar9e:周围有很多示例-如果您发现很难将其转换为您的特定方案,请在一个新问题中提供更多信息。
乔恩·斯基特

2
@alireza:我已经在第二段中给出了一个示例:通过使用不同的比较器,您可以通过不同的属性(年龄,姓名等)对同一集合(人员)进行排序。你不能这样做,只是通过使Person实现Comparable的,因为你不能再改怎么两个人进行比较。
乔恩·斯基特

1
@feelgoodandprogramming:不,这些是不同的排序算法。此处可能存在三段不同的三段代码:1)实体本身,例如Person。2)比较器,例如PersonAgeComparator,它能够比较两个不同的实体,并确定哪个应该以特定的排序顺序排在第一位。3)排序代码,它接受实体和比较器的集合,并使用比较器对集合进行排序以确定顺序。
乔恩·斯基特

2
@RishiKeshPathak:如果只比较一件显而易见的事情,那么使用Comparable的好处就更多了。即使这样,您也可以编写比较器。如果您有两个使用同一类的不同程序,而一个程序只想按年龄排序,而另一个只想按名称排序,则至少其中一个将需要使用比较器。
乔恩·斯基特

38

Comparable让类实现自己的比较:

  • 同一个班级(通常是一个优势)
  • 可以有只有一个实现(所以你不能使用,如果你想两种不同的情况)

相比之下,比较器是一个外部比较:

  • 它通常在唯一的实例中(在同一个类中或在另一个地方)
  • 为每个实现命名可以使用对事物进行排序的方式来
  • 您可以为您无法控制的类提供比较器
  • 即使第一个对象为null,实现也可用

在这两种实现中,您仍然可以选择要比较的内容。使用泛型,您可以声明为如此,并在编译时进行检查。这样可以提高安全性,但是确定合适的值也是一个挑战。

作为指导,在我设想的所有用例中,我通常使用可以与该对象进行比较的最通用的类​​或接口。:-(

  • Comparable<Object>使您可以在编译时在所有代码中使用它(如果需要,则很好,如果不需要,则不好,并且您松开了编译时错误);您的实现必须处理对象,并按需要但以可靠的方式进行转换。
  • Comparable<Itself> 相反,它非常严格。

有趣的是,当您将其自身子类化为子类时,子类还必须具有可比性并且对此具有鲁棒性(否则,它将破坏Liskov原理,并给您带来运行时错误)。


20

java.lang.Comparable

  1. 要实现Comparable接口,类必须实现单个方法compareTo()

    int a.compareTo(b)

  2. 您必须修改要对其实例进行排序的类。因此,每个类只能创建一个排序序列。

java.util.Comparator

  1. 要实现Comparator接口,类必须实现单个方法 compare()

    int compare (a,b)

  2. 您要构建一个与要对其实例进行排序的类分开的类。这样就可以为每个类创建多个排序序列。

14

Comparable 用于提供数据对象的默认顺序,例如,如果数据对象具有自然顺序。

A Comparator代表特定用途的订购本身。


8

Comparable通常是首选。但是有时候一个类已经实现了Comparable,但是您想对另一个属性进行排序。然后,您不得不使用Comparator

一些类实际上提供Comparators了常见的情况。例如,String默认情况下,s在排序时区分大小写,但也有一个Comparator称为的静态变量CASE_INSENSITIVE_ORDER


7
我不确定我是否赞成可比。有些对象具有很强的自然顺序感,即各种形式的数字:自然数,实数,日期等。但是,即使其他相对原始的对象(如字符串)也缺乏普遍适用的顺序。对于更复杂的对象(例如来自应用程序域模型的实体),实现Comparable通常是一个错误。它们的许多特性使得很难预测最需要什么顺序。
erickson

6

以下是我在网上发现的Comparator和Comparable之间的一些区别:

  1. 如果您看到然后这两者之间的逻辑差异是Java中的Comparator比较提供给他的两个对象,而Comparable接口则将“ this”引用与指定的对象进行比较。

  2. Java中的Comparable用于实现对象的自然排序。在Java API String中,Date和wrapper类实现Comparable接口。

  3. 如果任何类在Java中实现Comparable接口,则可以使用Collections.sort()或Array.sort()方法自动对List或Array的对象集合进行排序,并且对象将根据CompareTo方法定义的自然顺序进行排序。

  4. 可以在Java中实现Comparable的对象用作排序映射中的键或排序集中的元素(例如TreeSet),而无需指定任何Comparator。

站点:如何在Java中使用Comparator和Comparable?带例子

阅读更多:如何在Java中使用Comparator和Comparable?带例子


5

Comparable用于具有自然顺序的对象。对象本身知道如何排序。
Comparator用于没有自然顺序的对象,或者您希望使用其他顺序的对象。


4

比较器和可比较接口之间的区别

Comparable 用于与另一个对象进行比较。

Comparator 用于比较两个数据类型是对象。


2

如果您看到了,那么这两者之间的逻辑差异就是Comparator在Java中比较提供给他的两个对象,而Comparable接口将“ this”引用与指定的对象进行比较。

ComparableJava中的Java用于实现对象的自然排序。在Java API String中,Date和wrapper类实现Comparable接口。

如果有任何类实现Comparable界面在Java中则该对象的集合两种ListArray可以通过使用自动排序Collections.sort()Array.sort()方法和对象将基于由定义有自然顺序进行排序compareTo的方法。

例如,Comparable用Java 实现的对象可以用作排序映射中的键或排序集中的元素TreeSet,而无需指定任何对象Comparator


0

我的注释库,用于实现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);         
    }  
} 

单击链接以查看更多示例。比较的


3
欢迎来到stackoverflow。这个问题很旧,已经被回答了。通常,最好不要复活过时的线程,除非您的响应对以前的答案做出了明显的新贡献或与之前的答案有所不同。
oers 2012年
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.