为什么在Object中定义了equals和hashCode?

决定在java.lang.Object中包含这些方法的原因是什么? 对于许多类来说,平等和散列是没有意义的。

制作两个接口更合乎逻辑:

interface Equalable { boolean equals(Equalable other); } interface Hashable extends Equalable { int hashCode(); } 

例如,HashSet定义可能看起来像

 class HashSet ... 

它可以防止一个常见的初学者错误 – 使用一组项而不实现equals / hashCode。

当我们实现Interface我们inject (or accept)接口定义的契约。

EqualableHashable是两种不同的合约。 但是如果我们仔细观察一下,我们就会看到它们彼此依赖,这意味着它们是single interface一部分,比如EqualableAndHashable

现在显而易见的问题是,它们是否应该成为这个新的EqualableAndHashable接口或Object

让我们来看看。 我们有== (equal operator)来检查两个对象的相等性。 ==运算符确认两个不同的基元/对象的值/引用是否相等。 但是,通过使用==运算符进行检查并不总是可以回答。

现在的问题是,这个相等的同等性是否应该通过接口或Object类的一部分注入?

如果我们看看,我们不能只说:

TypeX不保证平等合同。

如果某些对象类型提供相等性而某些对象类型不提供,则会变得混乱。 这意味着TypeX对象必须遵守对所有其他对象类型都适用的相等契约。 因此,它不能从接口注入相等性,因为默认情况下,相等应该是任何对象的合同的一部分,否则会产生混乱。

所以我们需要Objects来实现equals实现。 但它不能只实现equals方法,它还需要实现hashcode方法。

java.lang.Object中的默认实现是有意义的。 很多时候,这已经够好了。 在JPA / Web应用程序中,我发现自己很少会覆盖equals和hashCode。

一个更好的问题可能是:对于String,Long等不可变值对象,为什么不能覆盖==运算符来调用equals(),就像在C#中一样? 我已经看到了更多的错误,因为这比我的默认equals / hashCode做得不对。 例如,

 Long x = obj.getId(); Long y = obj2.getId(); if (x == y) { // oops, probably meant x.equals(y)! } 

但是,这是一个公平的问题,为什么默认方法不会像默认的Object.clone()那样锁定在标记接口之后。 有一个默认实现,但您必须明确承认您希望通过实现Cloneable来使用它。 可以很容易地像Collectible或Equatable那样使用类似的标记接口,然后集合方法的签名可能是Equatable而不是Object。

Mhh不确定但是当Java 1.0发布时,generics还不存在。 它们是在2004年的Java 5.0中添加的。所以你的提议无法在Java 1.0中实现

最初,在Java中,没有generics。 这是通过允许任何Object成为任何集合的成员来解决的,因此任何Object需要hashCodeequals 。 到现在为止,它根本没有改变。

(就个人而言,如果他们在一个界面中,我会把它们放在那里,以避免至少有一类equals / hashCode错误。)

我认为你需要在Object中实现一个后备机制,这意味着无论如何一切都会有一个实现,接口与否。

我怀疑它很多都是历史性的; 编程Java今天看起来与编程Java有点不同。

如果你有一个对象列表,你调用contains方法应该用Java做什么? 我认为默认实现(比较参考)是一个不错的决定。 这样,您就不必为集合中使用的每个类实现自己的equalshashcode

它是一个通用的实现。 如果需要,您应该覆盖实现。 否则,您有一个合理的默认实现。

至少等于是必须的。 为基本操作创建接口可能会涉及很多开销。

真的,这只是为了方便,而且这种方式更好。 那么,如果你没有.equals方法,请考虑一下如何进行对象相等:

 AreEqual(Object obj1,Object obj2) { if(!obj1 instanceof Equalable) return false; if(!obj2 instanceof Equalable) return false; return ((Equalable)(obj1).equals((Equalable)obj2); } 

即使对于hashCode也是如此。 有时参考平等就足够了。 如果你让HashSet只接受实现Hashable的对象,那么你必须显式地使你的类Hashable,即使你只想要引用相等。 而且你已经减少了其他优秀数据结构的普遍性。

最好让Object有一个默认的(有时是足够的).equals和.hashCode函数,并为新来的人带来一些问题,而不是通过更多的繁文缛节让频繁的语言用户跋涉。

任何对象,无论其类型如何,都可以明智地回答它是否等同于任何其他对象,即使其他对象的类型是从未听过的类型。 如果从未听说过其他对象的类型,那么仅仅这个事实足以报告它不等同于后一个对象。