hashcode()和equals()方法

时间:2013-07-29 08:40:34

标签: java equals hashcode hashset

所以我对hashcode()和equals()方法有一个问题

假设我只是编写一个非常基本的程序来覆盖这两个方法

import java.util.*;

class Employee
{
   private String name;
   private int empid;


   public Employee(String name,int empid)
   {
       this.name=name;
       this.empid=empid;
   }


   public int getEmpid()
   {
       return empid;
   }


   public String getName()
   {
       return name;
   }


   public boolean equals(Object obj)
   {
       System.out.println("equals has just been called...");
       Employee e1=(Employee)obj;
       return ((name.equals(e1.name)) && (empid==e1.empid));
   }


   public int hashCode()
   {
       System.out.println("hashcode called...");
       return empid;
   }

}

然后,假设我写了另一个类来添加和迭代HashSet中的元素

class Five
{
   public static void main(String args[])
   {
       HashSet hs1=new HashSet();
       hs1.add(new Employee("Alex",25));
       hs1.add(new Employee("Peter",25));
       hs1.add(new Employee("Martin",25));
       hs1.add(new Employee("Alex",25));


       Iterator itr=hs1.iterator();

       while(itr.hasNext())
       {
           Employee e=(Employee)itr.next();
           System.out.println(e.getEmpid()+"\t"+e.getName());
       }


    }

}

现在的问题是  当我尝试使用相同的empid再次添加Alex时,equals()总是称为thee次

因为没有索引n hashmap所以如果首先用先前添加的Alex检查它将返回true并且不应该为其他两个元素调用(peter和martin) 但是等于总是被称为3次

为什么..?

同一桶内的对象也有索引.. ??

4 个答案:

答案 0 :(得分:12)

在添加和删除元素时,始终在java哈希集合中的Equals方法之后调用

hashCode。原因是,如果已经存在指定存储桶的元素,则JVM会检查它是否与它尝试放置的元素相同。如果equals返回false,则该元素将添加到同一个存储桶中,但位于存储桶列表的末尾。所以现在你只是在同一个桶中没有一个元素,而是一个元素列表。

现在,在检索元素时,将调用第一个hashCode以到达所需的存储桶,然后使用等于扫描列表以获取所需的元素。

hashCode的理想实现将确保每个桶的列表大小为1.因此,使用O(1)复杂度来完成元素的检索。但是如果存储在列表中的多个元素存储在桶中,那么元素的复制将由O(n)复杂完成,其中n是列表的大小。

在HashSet的情况下,没有在存储桶中创建列表,而是在hashcode和equals相同的情况下简单地替换对象。 ist创建行为在hashmap中。

答案 1 :(得分:3)

在插入期间,HashSet首先调用hashCode并查看新值属于哪个存储桶。它看到已经有三个条目(全部包含hashCode() 25)。

然后使用equals()进行比较。并且因为有3个条目,所以必须检查导致调用equals() 3次的所有条目。

答案 2 :(得分:3)

java.util.HashSet使用java.util.HashMap作为其存储空间。 java.util.HashMap使用链接的Entry对象来表示地图中的存储分区。如果您按照源代码进行操作,您将进入java.util.HashMap.Entry

的构造函数
Entry(int h, K k, V v, Entry<K,V> n) 
{
  value = v;
  next = n;
  key = k;
  hash = h;
}

通过此,您可以看到新项目已添加到存储桶的开头(代表存储桶的第一个Entry n的{​​{1}}),因此在您的情况下,存储桶中的项目(有)只有一个桶,因为每个Entry的哈希码是相同的)将按顺序排列:

Employee

因此,当第二次添加Alex时,在到达Alex之前检查每个值是否相等。

答案 3 :(得分:0)

具有相同散列的多个对象存储为LinkedList,并在HEAD添加新元素。因此,在您的情况下,因为所有都具有相同的散列,LinkedList按以下顺序:

  

上martin-&GT; Peter-&GT;阿莱克斯

当您添加另一个“Alex”时,列表将从HEAD遍历。

测试:

public boolean equals(Object obj)
   {
       Employee e1=(Employee)obj;
       System.out.println(this.name +  "'s equals has just been called against " + e1.name );
       return ((name.equals(e1.name)) && (empid==e1.empid));
   }
相关问题