关于java:hashcode()和equals()方法

hashcode() and equals() method

本问题已经有最佳答案,请猛点这里访问。

所以我有一个关于hashcode()和equals()方法的问题

假设我只写了一个非常基本的程序,它覆盖了两种方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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;
   }

}

然后,假设我编写另一个类来添加和迭代哈希集中的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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()总是调用you times

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

为什么。。??

同一个bucket中的对象是否也有索引..??


EDCOX1的0Ω总是在Java哈希集合中添加EDCOX1和1的方法之后调用,同时添加和移除元素。原因是,如果在指定的bucket中已经有一个元素,那么jvm会检查它是否是试图放入的同一个元素。如果equals返回false,那么元素将添加到同一个bucket,但在bucket的列表末尾。所以现在你不需要在同一个桶中有一个元素,而是一个元素列表。

现在,在检索元素时,首先调用hashcode以到达所需的bucket,然后使用equals扫描列表以获取所需的元素。

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

顺便说一句,对于hashset,bucket中没有创建列表,如果hashcode和equals相同,则只需替换对象。IST创建行为在哈希图中。


java.util.HashSet使用java.util.HashMap作为存储。java.util.HashMap使用链接的Entry对象表示地图中的存储桶。如果您按照源代码进行操作,您将到达java.util.HashMap.Entry的承包商:

1
2
3
4
5
6
7
Entry(int h, K k, V v, Entry<K,V> n)
{
  value = v;
  next = n;
  key = k;
  hash = h;
}

从中可以看出,新项目被添加到bucket的开头(Entry n表示bucket的第一个Entry),因此在您的情况下,bucket中的项目(由于每个Employee的哈希代码相同,所以只有一个bucket)将按以下顺序排列:

1
Martin -> Peter -> Alex

因此,当第二次添加alex时,在访问alex之前检查每个值是否相等。


在插入HashSet期间,首先调用hashCode并查找新值所属的存储桶。它发现已经有三个条目(所有条目都带有hashCode()25)。

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


多个具有相同哈希的对象存储为LinkedList,并在HEAD添加新元素。因此,在您的情况下,由于所有哈希都相同,LinkedList的顺序如下:

Martin->Peter->Alex.

当您添加另一个"alex"时,列表将从head遍历。

要测试:

1
2
3
4
5
6
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));
   }