如果有hashCode(),为什么Java需要equals()?

时间:2017-03-16 11:32:29

标签: java object

如果两个对象返回相同的hashCode,是不是意味着它们相等?或者我们需要等于防止碰撞?

我可以通过比较hashCodes来实现equals吗?

7 个答案:

答案 0 :(得分:19)

如果两个对象具有相同的hashCode,则它们不一定相等。否则你会发现完美的哈希函数。但事实恰恰相反 - 如果对象相等,那么它们必须具有相同的hashCode。

答案 1 :(得分:9)

hashCode 等于是有关对象的不同信息

考虑类似于哈希码为生日的人,

在那个场景中,你和许多其他人拥有相同的b-day(相同的哈希码),但是你不是同一个人...

答案 2 :(得分:3)

Oracle Docs中所述的hashCode方法是Java中对象的数字表示。此哈希码具有有限的可能值(由可以存储在int中的值表示)。

对于更复杂的类,您很可能会找到两个具有相同哈希码值的不同对象。此外,没有人阻止你在任何课程中这样做。

class Test {

    @Override
    public int hashCode() {
        return 0;
    }

}

因此,建议不要通过比较哈希码来实现equals方法。只有在可以保证每个对象都有唯一的哈希码时,才应将它们用于比较。在大多数情况下,您唯一可以肯定的是,如果两个对象使用 o1.equals(o2)相等,则 o1.hashCode()== o2.hashCode()。< / p>

equals方法中,您可以定义更复杂的逻辑来比较同一类的两个对象。

答案 3 :(得分:3)

  

如果两个对象返回相同的hashCode,那是不是意味着它们是相等的?

不,这并不意味着。

.dropdown-menu { margin-left: 10px; } .dropdown-menu > li { padding-left: 10px } Object说明了这一点:

  

hashCode的一般合同是:

     
      
  • 每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终如一   如果equals中没有使用任何信息,则返回相同的整数   对象的比较被修改。 ...
  •   
  • 如果根据equals(Object)方法两个对象相等,则必须对两个对象中的每一个调用hashCode方法   产生相同的整数结果。
  •   
  • 根据equals(java.lang.Object)方法,如果两个对象不相等,则不需要调用hashCode方法   两个对象中的每一个都必须产生不同的整数结果。 ...
  •   

请注意突出显示的声明。它明确地对你的问题说“不”。

还有另一种方法来看待这个。

  1. hashCode会返回int
  2. int只能有2个 32 不同的值。
  3. 如果a.hashCode() == b.hashCode()暗示a.equals(b),那么在正在运行的Java应用程序中,任何给定时间只能有2个 32 不同(即互不相等)的对象。
  4. 最后一点显然不正确。实际上,如果你有足够大的堆来容纳64位JVM中的java.lang.Object的2个 32 实例,那么这显然不是真的。

    第三种方法是一些众所周知的例子,其中两个不同的两个字符串具有相同的哈希码。

    鉴于您的假设不正确,其后面的推理也是不正确的。

    1. Java 需要equals方法。
    2. 您通常无法仅使用equals实施hashCode
    3. 您可以使用hashCode来实现更快的equals方法,但只有在调用hashCode两次比比较两个对象更快的情况下才会这样做。通常不是。

答案 4 :(得分:2)

hashCodes是相等的 - &gt;对象可能相同 - &gt;需要进一步比较 hashCodes是不同的 - &gt;对象不相等(如果hashCode实现正确)

这是如何实现equals方法的。首先,检查hashCodes是否相等。如果是,则需要检查类字段以查看它是否代表完全相同的对象。如果hashCodes不同,您可以确定对象不相等。

答案 5 :(得分:2)

  

如果有hashCode(),为什么Java需要equals()?

Java需要public class And implements Predicate{ private Predicate pred1; private Predicate pred2; public And(Predicate p1, Predicate p2){ this.pred1 = p1; this.pred2 = p2; } @Override public boolean eval(){ return this.pred1.eval() && this.pred2.eval(); } @Override public void execute(){ // Not sure of you want to do here } } public class NameIsSet implements Predicate{ private String name; public NameIsSet (String name){ this.name = name; } @Override public boolean eval(){ return this.name == null || this.name.length = 0; } @Override public void execute(){ // Not sure of you want to do here } } ,因为它是通过检查设计者认为是等于测试的一部分的类,字段和其他条件来测试对象相等性的方法。

equals()的目的是提供主要供哈希表使用的哈希值;虽然它也可以用于其他目的。返回的值基于对象的字段和复合和/或聚合对象的哈希码。该方法没有考虑对象的类或类型。

hashCode()equals()之间的关系是一种含义。

  • 两个相等的对象意味着它们具有相同的哈希码。
  • 具有相同哈希码的两个对象意味着它们是相同的。

后者由于以下几个原因而不成立:

  • 两个不同的对象有可能返回相同的哈希码。请记住,哈希值会将大量数据中的信息折叠成较小的数字。
  • 来自具有相似字段的不同类的两个对象很可能使用相同类型的散列函数,并返回相等的散列值;然而,它们并不相同。
  • hashCode()可以是特定于实现的,在不同的JVM或JVM目标安装上返回不同的值。

在同一个JVM中,hashCode()可以通过先测试已知的哈希码,并且只有在相同的测试实际相等时才能用作平等的廉价前兆;只要相等测试比生成哈希码要昂贵得多。

  

我可以通过比较hashCodes来实现equals吗?

没有。如上所述,相等的哈希码并不意味着相等的对象。

答案 6 :(得分:1)

有时(很多时候?)你不会!

这些答案并非不真实。但他们并不能讲述整个故事。

一个示例是您正在创建类SomeClass的对象加载,并且通过递增静态变量nInstanceCount或其他一些实例,为每个创建的实例提供唯一ID,在构造函数中:

iD = nInstanceCount++;

您的哈希函数可以然后

int hashCode(){
    return iD;
}

你的等于 然后

boolean equals( Object obj ){
    if( ! ( obj instanceof SomeClass )){
        return false;
    }
    return hashCode() == obj.hashCode();
}

...在这种情况下,你的想法是等于多余的&#34;确实如此:如果所有类都表现得像这样,Java 10(或Java 23)可能会说,啊,让我们摆脱愚蠢的旧equals,重点是什么? (NB向后兼容性将会出现在窗口之外)。

有两个要点:

  • 您无法创建MAXINTSomeClasslong个实例。或者......您 可以 ...如果您设置了一个系统来重新分配以前销毁的实例的ID。 ID通常为int而不是hashCode() ...但这不起作用,因为int会返回HashMap

  • 这些对象中没有一个可以&#34;等于&#34;另一个,因为你已经定义了这个特定类的 equality = identity 。通常这是可取的。它通常会关闭各种可能性......

你的问题的必要含义可能是这两种方法的用途,这些方法以一种相当烦人的方式必须“合作”。在他/她的回答中,Frelling提到了关键点:需要使用哈希码来排序&#34;桶和#34;像HashMap这样的类。值得一读的是:非常值得设计高效数据的高级数学数据&#34;桶&#34;像hashCode()这样的类的机制非常可怕。在阅读之后,你可能会(像我一样)对你应该如何以及为什么要费心去实施content.featured == "featured有一点理解和敬畏!