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

时间:2011-11-13 18:39:45

标签: java oop equals hashcode

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

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

interface Equalable {
    boolean equals(Equalable other);
}

interface Hashable extends Equalable {
    int hashCode();
}

例如,HashSet定义可能类似于

class HashSet<T extends Hashable> ...

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

9 个答案:

答案 0 :(得分:14)

当我们实现Interface我们inject (or accept)接口定义的合同时。

Equalable&amp; Hashable是两个不同的合同。但是如果我们仔细观察一下,我们就会看到它们彼此依赖,这意味着它们是single interface的一部分,类似于EqualableAndHashable

现在显而易见的问题是,它们是否应该成为新EqualableAndHashable界面或Object的一部分?

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

现在的问题是,这个等式which is also a contract是否应该通过接口或Object类的一部分注入?

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

  

TypeX不保证平等合同。

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

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

答案 1 :(得分:2)

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

更好的问题可能是:对于String,Long等不可变值对象,为什么不能覆盖==运算符来调用equals(),就像在C#中一样?我已经看到了更多的错误,因为我的默认等于/ 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。

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

真的,这只是为了方便,而且这种方式更好。那么,如果你没有.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函数,并为新来的人带来一些问题,而不是让频繁的语言用户通过更多繁文缛节跋涉。

答案 8 :(得分:0)

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