hashcode()和equals()方法

所以我对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)调用但是equals总是被调用3次

为什么..??

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

在添加和删除元素时,始终在java哈希集合中的hashCode方法之后调用Equals 。 原因是,如果某个元素已经存在于指定的存储桶中,那么JVM会检查它是否与它尝试放置的元素相同。 如果等于返回false,则该元素将添加到同一个存储桶,但位于存储桶列表的末尾。 所以现在你只是在同一个桶中没有一个元素,而是一个元素列表。

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

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

顺便说一下,在HashSet的情况下,没有在桶中创建列表,而是如果hashcode和equals相同则简单地替换对象。 ist创建行为在hashmap中。

java.util.HashSet使用java.util.HashMap作为其存储。 java.util.HashMap使用链接的Entry对象来表示地图中的存储桶。 如果您仔细阅读源代码,您将获得java.util.HashMap.Entry的构造函数:

 Entry(int h, K k, V v, Entry n) { value = v; next = n; key = k; hash = h; } 

从这里你可以看到新项目被添加到桶的开头( Entry n代表桶的第一个Entry ),所以在你的情况下桶中的项目(只有一个桶,因为每个桶的哈希码Employee是一样的)将在订单中:

 Martin -> Peter -> Alex 

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

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

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

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

上martin-> Peter->亚历克斯。

当您添加另一个“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)); }