compare()和compareTo()有什么区别?

121

Java中compare()compareTo()方法有什么区别?这两个方法是否给出相同的答案?


1
你指的是哪个比较类方法? - Markus Lausberg
请参阅以下链接,详细了解compare()和compareTo()的用法:http://sysdotoutdotprint.com/index.php/2017/03/28/comparable-vs-comparator/ - mel3kings
@mel3kings,您能否更新您的评论中的链接?它目前对这个问题没有提供任何信息。 - CJay Horton
16个回答

177

来自JavaNotes

  • a.compareTo(b):
    Comparable接口:比较值并返回一个整数,指示这些值是小于、等于还是大于。如果你的类对象有自然顺序,请实现Comparable<T>接口并定义此方法。所有有自然排序的Java类都实现了Comparable<T> - 例如:Stringwrapper classesBigInteger

  • compare(a, b):
    Comparator接口:比较两个对象的值。它作为Comparator<T>接口的一部分实现,并且典型的用法是定义一个或多个小型实用程序类来实现它,以传递给sort()等方法,或用于排序数据结构,如TreeMapTreeSet。您可能想为以下情况创建一个Comparator对象:

    • 多个比较。提供多种不同的排序方式。例如,您可能希望按名称、ID、年龄、身高等对Person类进行排序。您将为每个这些定义一个Comparator对象,以传递给sort()方法。
    • 系统类。为您无法控制的类提供比较方法。例如,您可以为字符串定义一个Comparator,按长度进行比较。
    • 策略模式。实现策略模式,这是一种情况,在这种情况下,您希望将算法表示为可以作为参数传递、保存在数据结构中等的对象。
如果您的类对象有一个自然排序顺序,那么您可能不需要使用compare()。

来自http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html的总结:

Comparable
实现了Comparable接口的对象可以与其他对象进行比较。

Comparator
实现了Comparator接口的对象可以比较两个不同对象。该类并非比较其实例,而是另一个类的实例。


使用案例上下文:

可比较接口

equals方法和==!=运算符测试相等/不相等,但没有提供一种测试相对值的方法
一些类(例如,具有自然排序的String和其他类)实现了Comparable<T>接口,该接口定义了一个compareTo()方法。
如果您想要将其与Collections.sort()Arrays.sort()方法一起使用,则需要在您的类中实现Comparable<T>

定义Comparator对象

您可以创建Comparators以任意方式为任何类进行排序
例如,String类定义了CASE_INSENSITIVE_ORDER比较器


两种方法的区别可以归结为以下概念:
有序集合: 当集合被排序时,它意味着你可以按照特定(非随机)顺序迭代集合(Hashtable 不是有序的)。
自然排序的集合不仅仅是有序的,而且还是排序的。定义自然排序可能很困难!(如字符串的自然排序)。

另一个区别,HaveAGuess评论中指出:

  • Comparable 在实现中而不是从接口中可见,因此当您进行排序时,您并不真正知道会发生什么。
  • Comparator 使您确信排序将被定义良好。

3
由于这个答案是详尽的,这里有一些关于 Comparable 让我烦恼的事情,你可能想要添加进去:它在实现中而不是从接口中可见,因此当你进行排序时,你实际上并不知道会发生什么。使用比较器可以让你放心,排序将被定义得很好。 - HaveAGuess
@HaveAGuess 很好的观点。我已经将您的评论包含在答案中,以增加其可见性。 - VonC
对象具有自然顺序,这里的自然顺序是什么意思?例如员工类中的字符串数据成员名称是否具有自然顺序? - Narendra Jaggi
@NarendraJaggi 请参阅https://en.wikipedia.org/wiki/Enumeration。一种便于枚举的顺序。“自然”是指给定索引集上的良序提供了一种唯一的方法来列出下一个元素,而不是部分枚举。 - VonC
2
@VedantKekan 谢谢你。我已经在这个答案中恢复了2个链接。 - VonC

18

compareTo() 是从 Comparable 接口中来的。

compare() 是从 Comparator 接口中来的。

这两个方法实现的功能是相同的,但每个接口在略微不同的上下文中使用。

Comparable 接口用于对实现类的对象强制进行自然顺序排列。 compareTo() 方法被称为自然比较方法。 Comparator 接口用于对实现类的对象强制进行总排序。有关更多信息,请参见何时使用每个接口的链接。


你能给一些例子吗?这两种方法得出的答案相同吗? - Eggs McLaren
我不知道为什么“Comparable”是用于自然排序的?我们不能自定义它吗? - c-an

14

相同点:
两者都是比较两个对象的自定义方式。
两者都返回一个描述两个对象关系的int

不同点: compare() 方法是如果你实现 Comparator 接口,则必须要实现的一个方法。它允许你将两个对象传递到该方法中,并返回一个描述它们关系的int

Comparator comp = new MyComparator();
int result = comp.compare(object1, object2);

compareTo()方法是实现Comparable接口时必须实现的方法。它允许将一个对象与相似类型的其他对象进行比较。

String s = "hi";
int result = s.compareTo("bye");

总结:
基本上它们是比较事物的两种不同方式。


10

这些方法并不一定会得到相同的答案,这取决于你调用哪些对象/类。

如果你正在实现自己的类,并且知道在某个阶段你想进行比较,你可以让它们实现Comparable接口,并相应地实现compareTo()方法。

如果你使用的是一些API中未实现Comparable接口的类,但仍想进行比较,例如排序。你可以创建一个实现了Comparator接口的自定义类,在其compare()方法中实现逻辑。


6

使用 Comparator,我们可以为一个类编写n个比较逻辑

例如:

对于汽车类

我们可以有一个比较器类来根据汽车型号进行比较。我们也可以有一个比较器类来根据汽车型号年份进行比较。

汽车类

public class Car  {

    int modelNo;

    int modelYear;

    public int getModelNo() {
        return modelNo;
    }

    public void setModelNo(int modelNo) {
        this.modelNo = modelNo;
    }

    public int getModelYear() {
        return modelYear;
    }

    public void setModelYear(int modelYear) {
        this.modelYear = modelYear;
    }

}

以型号为基础的比较器 #1

public class CarModelNoCompartor implements Comparator<Car>{

    public int compare(Car o1, Car o2) {

        return o1.getModelNo() - o2.getModelNo();
    }

}

基于车型年份的比较器#2

public class CarModelYearComparator implements Comparator<Car> {

    public int compare(Car o1, Car o2) {

        return o1.getModelYear() - o2.getModelYear();
    }

}

但是在 Comparable 接口的情况下,这是不可能的。

对于 Comparable 接口,我们只能在 compareTo() 方法中编写一种逻辑


5

Comparable接口包含一个名为compareTo(obj)的方法,该方法只接受一个参数,并将自身与同一类的另一个实例或对象进行比较。

Comparator接口包含一个名为compare(obj1,obj2)的方法,该方法接受两个参数,并比较来自同一或不同类的两个对象的值。


4
compareTo(T object)

这里介绍的是来自java.lang.Comparable接口的内容,该接口用于比较当前对象和另一个对象,返回负整数表示当前对象小于另一个对象,0表示相等,正整数表示当前对象大于另一个对象。这是一种更方便的比较方法,但需要在每个要进行比较的类中实现。

compare(T obj1, T obj2)

这里的内容来自于java.util.Comparator接口,实现在一个独立的类中,用于比较另一个类的对象,给出负整数值表示第一个对象小于,0表示相等,正整数值表示第二个对象大于。当你无法让一个类实现compareTo()方法因为它是不可修改的时候,就需要使用它。同时,当你想要使用不同的方式来比较对象时,而不仅仅是通过名称或年龄来比较时,也可以使用它。


3
这个方法的对象与其协作者的关系是不同的。 compareTo() 是接口Comparable的一个方法,因此它用于将该实例与另一个实例进行比较。 compare() 是接口Comparator的一个方法,因此它用于比较另一类的两个不同实例。
如果您愿意,实现Comparable意味着可以轻松比较该类的实例。
实现Comparator意味着该类的实例适合比较不同对象(其他类的对象)。

2

compareTo()是在一个对象上调用的,用于将其与另一个对象进行比较。 compare()是在某个对象上调用的,用于比较另外两个对象。

区别在于定义实际比较逻辑的位置不同。


不是我所谓的一个很棒的答案,但我认为它不应该被踩。 - Paul Tomblin
同意,就个人而言,我会保留踩掉错误或误导性的答案。这个答案绝对是正确的。 - Joachim Sauer
那些给我点踩的“友好”人在哪里呢?这是我的第二个正确答案,因为有人没有理解问题而被点踩了。不知道是点踩的意义还是我的回答的意义被忽略了。生活真是残酷啊..;-) - Abgan

2

主要区别在于接口的使用:

Comparable(具有compareTo()方法)要求被比较的对象(为了使用TreeMap或对列表进行排序)实现该接口。但是如果类没有实现Comparable并且您无法更改它,因为它是第三方库的一部分怎么办?那么您必须实现一个Comparator,这样使用起来会稍微不太方便。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接