【问题标题】:Hashcode() Vs Equals()Hashcode() 与 Equals()
【发布时间】:2012-08-07 17:17:32
【问题描述】:

我有下面这两个类..

class Emp //implements Comparable
{
      String name,job;
      public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getJob() {
        return job;
    }
    public void setJob(String job) {
        this.job = job;
    }
    public int getSalary() {
        return salary;
    }
    public void setSalary(int salary) {
        this.salary = salary;
    }
    int salary;
      public Emp(String n,String j,int sal)
      {
         name=n;
         job=j;
         salary=sal;
       }
      public void display()
      {
        System.out.println(name+"\t"+job+"\t"+salary);
       }



  public boolean equals(Object o)
      {

         Emp p=(Emp)o;
          return this.name.equals(p.name)&&this.job.equals(p.job) &&this.salary==p.salary;
       }
  /* public int hashCode()
       {
          return name.hashCode()+job.hashCode()+salary;
       }
     */

      /* public int compareTo(Object o)
       {
          Emp e=(Emp)o;
          return this.name.compareTo(e.name);
           //return this.job.compareTo(e.job);
        //   return this.salary-e.salary;

        }*/
} 

另一个是..

import java.util.*;
class EmpHsDemo
{
      public static void main(String arg[])
      {
          HashSet set=new HashSet();
          set.add(new Emp("Ram","Trainer",34000));
          set.add(new Emp("Ram","Trainer",34000));
          set.add(new Emp("Ravi","Administrator",44000));
          set.add(new Emp("Sachin","Programmer",24000));
          set.add(new Emp("Priyanka","Manager",54000));
          set.add(new Emp("Anupam","Programmer",34000));
          set.add(new Emp("Sachin","Team Leader",54000));
          System.out.println("There are "+set.size()+" elements in the set.");
          System.out.println("Content of set are : ");
          Iterator itr=set.iterator();
          while(itr.hasNext())
          {
            Emp e=(Emp)itr.next();
            System.out.print(e.hashCode()+"\t");   
            e.display();
          }   


          System.out.println("**********************************");
        Emp e1=new Emp("Ravi","Administrator",44000);
        System.out.println("Removing following Emp from the set...");
        System.out.print(e1.hashCode()+"\t");
        e1.display();
        set.remove(e1);
        System.out.println("No. of elements after removal "+set.size());
       /* Emp e2=new Emp("Anupam","Programmer",34000);
        System.out.println("Searching following Emp in the set...");
        System.out.print(e2.hashCode()+"\t");
        e2.display();
        System.out.println("Results of searching is : "+set.contains(e2));*/
      }
}

现在我正在做一项研究,即

  1. 如果我注释 hashcode() 方法而不是注释 equals () 方法,它将使用它允许重复,因为 Ram 与内存地址一起显示两次,我得到以下结果..
There are 7 elements in the set.
Content of set are : 
374283533   Priyanka    Manager 54000
1660364311  Ram Trainer 34000
1340465859  Ravi    Administrator   44000
2106235183  Sachin  Programmer  24000
2031692173  Ram Trainer 34000
603737068   Anupam  Programmer  34000
148669801   Sachin  Team Leader 54000
**********************************
Removing following Emp from the set...
1807500377  Ravi    Administrator   44000
No. of elements after removal 7

2 。如果我取消注释 hashcode() 方法和 equals() 方法,我会得到这个结果

There are 6 elements in the set.
Content of set are : 
1546622676  Sachin  Team Leader 54000
-302767206  Anupam  Programmer  34000
149315535   Ravi    Administrator   44000
199998062   Sachin  Programmer  24000
1407883922  Priyanka    Manager 54000
597555555   Ram Trainer 34000
**********************************
Removing following Emp from the set...
149315535   Ravi    Administrator   44000
No. of elements after removal 5

3 .如果我只评论 equals() 方法而不评论 hashcode() 那么我得到以下结果

There are 7 elements in the set.
Content of set are : 
1546622676  Sachin  Team Leader 54000
-302767206  Anupam  Programmer  34000
149315535   Ravi    Administrator   44000
199998062   Sachin  Programmer  24000
1407883922  Priyanka    Manager 54000
597555555   Ram Trainer 34000
597555555   Ram Trainer 34000
**********************************
Removing following Emp from the set...
149315535   Ravi    Administrator   44000
No. of elements after removal 7

请告知这三种方法背后的原因..!

【问题讨论】:

标签: java collections hashset


【解决方案1】:

不值得阅读您发布的所有信息。

Joshua Bloch 说 hashCode 和 equals 应该一起被覆盖。 Here's应该怎么做,没有例外。

【讨论】:

  • 是和不是。一方面,是的——这是Java 中的绝对 事物之一。另一方面,强烈而响亮的不 - 您应该始终在申请之前尝试了解某事是如何运作的,而不仅仅是基于权威声明。
  • 我明白,我同意这个案子的权威。如果你是投反对票的人,我会说你是不正确的人,而不是我。我认为 Java Collections API 的作者知道他的 API 需要什么,在这种情况下具有足够的权威性。由于 OP 使用的是 Java 集合,他/她应该遵循建议。
  • @pafau 我同意我们应该在权威声明之外给出解释。看起来也很愚蠢,因为他链接了 Effective Java 的章节,该章节解释了为什么 hashcode/equals 教条存在的来龙去脉。他唯一没有做的就是说“第 8 条专门处理 hashcode/equals”,但老实说,整章对所有 Java 程序员来说都是必不可少的。
【解决方案2】:

一个 HashSet 有许多桶。它使用hashCode() 来确定一个元素属于哪个桶,然后在该桶中,它使用equals() 来查找该元素是否存在于该桶中。

这些方法的默认实现是hashCode() 使用系统标识哈希码,这可能是它的内存位置,但它的独特之处在于系统将尝试使用所有“合理实用”的尝试来使没有两个对象具有相同的系统标识哈希码,equals 比较两个对象的内存位置。 (请注意,系统身份哈希码不能保证产生唯一的哈希值;相反,它会非常、非常、非常努力地为您提供唯一的哈希值。请参阅Java Bug 6321873 以了解有关此事的进一步阅读。)

因此,有了这些知识,可以通过对各种方法的逻辑应用来预测不同的方法,无论它们是已实现还是使用默认实现。

在您的第一种情况下,Ram 出现在两个不同的存储桶中,因此这两个 Ram 对象永远不会相互比较。它们使用以下行进行比较(至少在 Sun 实现中)

if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

这是遍历桶中的每个对象。它们的哈希值不相等,因此永远不会检查确定对象本身是否等于提供的值。

在您的第二种情况下,它可以按您预期的那样工作,注意具有两个不同职位和薪水的人将被视为不同的人。

在您的第三种情况下,Ram 两次进入同一个存储桶。但是因为使用了默认的equals方法,并且两个对象是不同的对象,所以会被第二次添加。

同样值得重申的是,duffymo 的回答完全忽略了您的问题;在 99.9% 的情况下,我会说这是错误的做法,我们应该首先了解您的问题范围。这是可以正确调用忽略您的问题的极少数情况之一。您应该从不只覆盖 hashcode 和 equals 之一。您应该始终都不做或两者都做,永远不要只做一个。

【讨论】:

  • 你的第二句话不正确。系统身份哈希码不能保证对每个对象都是唯一的。该规范不强制执行任何此类约束。
  • 这实际上是我的第三句话:-)。我实际上不知道它没有被指定。我已经添加了必要的信息。谢谢!
【解决方案3】:

1.2个对象相等那么他们应该有same hashcode

2.如果 2 个对象有 same hascode,,那么它们必须互相调用 equals() 来查看它们是否相等。

3.如果哈希码匹配其不一定它们都相等。

4.所以它非常重要equals()方法被覆盖那么,hashcode()方法也必须是被覆盖。

5. HashSet 在获取对象时检查该对象在 HashSet 中的位置,然后是否有任何具有相同哈希码的对象, 如果有那么两者都被放入一个桶中,并以same hashcode 作为标签,然后在彼此上调用equals() 以查看,如果它们真的相等。

【讨论】:

    【解决方案4】:

    HashSet 使用HashMap 作为数据的内部表示。 HashSet.add()HashSet.remove() 处理 hash 值(您在 hashCode() 方法中提供。一旦您将 hashCode() 评论出来,所有赌注都将取消。

    在这件事上,我的心在某种程度上与达菲莫有关,但另一方面,我几乎同样恶毒地反对做某事,因为你的权威在不理解的情况下告诉了你。

    【讨论】:

    • 在我看来,你没有理解这里的权威。上下文是 Java 集合,这些数据结构的正确操作建议来自设计它们的个人。
    【解决方案5】:

    corsiKa 回答正确。只需添加几个点来简化事情。 @user1582269 您正在使用 Set Algo 和 Hashing 是使用了数据结构。 根据 Set 概念 - Set 中的每个元素都应该是唯一的。不允许重复元素。 在哪个基础上元素将是独一无二的?为了实现这种唯一性,应该重写 equals() 方法。即 Emp 1 应该与 Emp 2 不同。 现在您正在使用 Hash Data Structure 。散列确保如何存储、检索和搜索元素。为了让散列有效地工作散列函数,即 hashCode() 应该被覆盖,这样就不会有任何冲突。

    corsiKa 的解释应该阅读更多关于散列的解释。 因此,如果您不覆盖 hashCode(),默认 hashCode() 实现将返回一些存储桶 id(假设数组中有一些索引),例如4. 所以如果empX元素已经存储在桶id 4,并且对于另一个员工empY相同的hashCode,即返回4,那么empX和empY之间就会发生冲突。

    希望这能澄清您的疑问。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-29
      • 2013-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-02
      • 2021-03-11
      相关资源
      最近更新 更多