为什么.equals()在Java中的类中时,为什么.compareTo()在接口中?


30

我想知道为什么类中有类似方法的同时.compareTo()Comparable接口.equalsObject。在我看来,为什么.compareTo()没有这样的方法似乎是武断的Object类中。

要使用.compareTo(),您可以实现Comparable接口并根据需要实现.compareTo()方法。对于该.equals()方法,您只需在类中重写该方法,因为所有类都从Object该类继承。

我的问题是,为什么.compareTo()在您实现的接口中而不是在像这样的类中实现这样的方法Object?同样,为什么要.equals()在类中Object而不是在某些接口中实现该方法?



2
这是Java语言的设计选择(不一定意味着它是正确的选择)。在其他语言中,例如Haskell,您必须实现相等接口以获取值相等(实际上,您为Eqtypeclass 提供了一个实例)。
mucaho 2015年

Answers:


58

并非可以比较所有对象,但是可以检查所有对象是否相等。如果没有其他问题,则可以看到两个对象是否在内存中的同一位置(引用相等)。

compareTo()对两个Thread对象意味着什么?一个线程如何比另一个线程“更大”?您如何比较两个ArrayList<T>S?

Object合同适用于所有 Java类。如果甚至一个类都无法与自己类的其他实例进行比较,那么Object就不能要求它成为接口的一部分。

约书亚·布洛赫(Joshua Bloch)在解释类可能要实现的原因时使用了关键字“自然排序” Comparable。正如我在上面的示例中提到的,并不是每个类都有自然的顺序,所以不是每个类都应该实现Comparable也不应该Object具有该compareTo方法。

... compareTo方法未在中声明Object。...它的特性与Objectequals方法类似,不同之处在于它除了允许简单的相等比较之外还允许顺序比较,并且它是通用的。通过实现Comparable,一个类指示其实例具有自然顺序

有效的Java,第二版:Joshua Bloch。项目62,第62页。省略号删除了对其他章节和代码示例的引用。

对于确实要对Comparable没有自然顺序的非类施加顺序的情况,您始终可以提供Comparator实例来帮助对其进行排序。


3
当您开始考虑带有Exception的compareTo时(这不是一个抽象类,因此会实现它,这意味着aNullPointerException.compareTo(anUnsupportedFlavorException)将具有...的含义,这会带来更多的乐趣?

10
可以检查所有对象的相等性。在Java中是,但通常不是。有一些对象示例中的相等比较没有意义(甚至没有引用相等)-例如单例。可能有ValueEquality和ReferenceEquality之类的接口(抽象类)。它甚至可能不是一个坏主意……
qbd 2015年

5
“可以检查所有对象是否相等。如果没有其他问题,则可以查看两个对象是否在内存中的同一位置(引用相等)。” -因为我们确实有==后者,所以它有一个空心环。忽略冗余默认值,可以找到不对equals所有类都假定的正当理由,因为并非所有类型都可以支持等价关系。
拉斐尔2015年

3
定义相等并不明智的两个类型的示例:流(例如,潜在的无限无限列表或无限精度数字)和函数。前者的问题是建立平等可能需要无限地进行比较。无法确定两个函数是否相等。询问这些类型的两个实例是否存在于相同的内存位置中是:1)不太有用,2)允许客户端编写对实现细节应该敏感的代码。今天,我可能会在您每次询问时给您一个相同的无限列表的新实例,明天我可能会记住它。
2015年

6
@Snowman它无用的事实与暴露实现细节的事实相结合,这是有足够的理由不允许这样做。Java 8中几乎每个“基于值”的类都有一个样板,上面写着“如果您使用,我们将不承担任何责任==”,因为这些类的实例化方式是实现细节,但是这种语言无法隐藏。您可以说任何Integer通过引用比较两个s的人都是白痴,但是允许比较开始是愚蠢的。
2015年

8

§4.3.2JLS定义了class以下列方式对象:

4.3.2。类对象

班级 Object是所有其他类的超类(第8.1.4节)。

所有类和数组类型都继承(第8.4.8节)class的方法,Object概述如下:

  • 该方法clone用于复制对象。

  • 该方法equals定义了对象相等的概念,该概念基于值,而不是引用,比较。

  • finalize仅在销毁对象之前运行该方法(第12.6节)。

  • 该方法getClass返回代表对象类的Class对象。

  • Class每个引用类型都有一个对象。例如,可以使用它来发现类的完全限定名称,其成员,其直接超类以及其实现的任何接口。

    方法调用表达式的类型getClassClass<? extends |T|>,其中T搜索的类或接口(第15.12.1节)在哪里getClass

    声明的类方法synchronized(第8.4.3.6节)在与该类的Class对象关联的监视器上同步。

  • 该方法hashCode与equals一起在诸如的哈希表中非常有用java.util.Hashmap

  • 方法waitnotifynotifyAll用于使用线程的并行编程中(第17.2节)。

  • 该方法toString返回对象的String表示形式。

所以,这就是为什么equalsObject,但compareTo在一个单独的接口。我推测他们想保持Object尽可能少。他们大概计算过,几乎所有的 Objects需要equalshashCode(这是真的只是一个平等的测试形式),但不是所有的对象都需要有一个概念排序,这是compareTo用于。


我猜理论上可能会有一个接口,Equitable<T>但是如果Object实现了它,那么每个类都是一个接口Equitable<Object>。那时有区别吗?实际上并非如此,复杂性是。
曼队长

1
就像Java中一样,.Net中的@CaptainMan object具有Equals(object),但也有IEquatable<T>接口。尽管它存在的主要原因是要避免在T值类型为box时装箱,这在Java中是不可能的。
2015年

hashCode 不是相等性测试的一种形式,因为存在哈希冲突。如果A和B相等,则它们具有相同的hashCode,但是如果A和B具有相同的hashCode,则并不意味着它们相等!
2015年

实际上,您的答案将从切换到较旧的JLS(Titan.cs.berkeley.edu/doc/java-langspec-1.0.pdf)中受益匪浅-它对直接equals声明原因的引用要好得多ObjectThe methods equals and hashCode are declared for the benefit of hashtables such as java.util.Hashtable (§21.7)-作为Java设计是向后兼容的,因此Java 1.0设计的选择才是正确的equals
vaxquis's

因为我建议的编辑可能会因为“太过激”而被拒绝,以防万一您只想按Ctrl + C / Ctrl + V将相关内容输入您的答案:pastebin.com/8c4EpLRX
vaxquis

2

除了Snowman的出色回答外,请记住,Comparable很长一段时间以来,它一直是通用接口。一个类型不实现compareTo(object),它实现compareTo(T)where T是它自己的类型。这不能在上实现object,因为object不知道将从其派生的类。

object可以定义一个compareTo(object)方法,但这不仅可以让Snowman指出,也可以允许两个ArrayList<T>s或两个Threads之间的比较,甚至允许an ArrayList<T>和a 之间的比较Thread。这更荒谬。


0

假设我有两个对象引用:X标识String持有内容“ George” 的实例;Y表示Point保存坐标的实例[12,34]。请考虑以下两个问题:

  • X和Y是否标识等效对象?

  • X应该在Y之前,之后还是与Y排序?

X和Y标识无关类型的实例这一事实在考虑第一个问题时不会造成任何问题。仅当对象的类型共享一个将它们定义为等效对象的公共基础时,才可以将它们视为等效对象。由于StringPoint没有这样的基数(它们唯一的公共基类型将所有不同的对象都视为非等效对象),答案就是“否”。

但是,类型无关的事实对第二个问题提出了巨大的问题。一些类型定义了它们的实例之间的排序关系,而某些排序关系甚至可以扩展到多种类型(例如,有可能BigIntegerBigDecimal定义比较方法,以允许将任一类型的实例相对于另一类型的实例进行排名),但是通常不可能采取两个任意实例并询问“应该X在Y之前,之后还是等效于Y排序”并得出总排序。如果要求对象报告一致的顺序(虽然不是总数),则可能会问“应该在X之前,之后,等同或相对于Y进行排序吗”一种,但是大多数排序算法都要求总排序。因此,即使compareTo“ unranked”是有效的返回值,即使所有对象都可以实现一个方法,这种方法也不足以证明其存在的合理性。

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.