Java hashCode()和equals()

时间:2020-01-09 10:35:47  来源:igfitidea点击:

方法hashCode()和equals()在插入Java集合的对象中起着不同的作用。最好在JavaDoc中描述这两种方法的特定合同规则。在这里,我只告诉我们他们扮演的角色。它们的用途是什么,所以我们知道为什么它们的实现很重要。

equals()

" equals()"在大多数集合中用于确定集合是否包含给定元素。例如:

List list = new ArrayList();
list.add("123");

boolean contains123 = list.contains("123");

ArrayList迭代所有元素并执行" 123" .equals(element)以确定元素是否等于参数对象" 123"。是String.equals()的实现,它确定两个字符串是否相等。

删除元素时也使用了equals()方法。例如:

List list = new ArrayList();
list.add("123");

boolean removed = list.remove("123");

ArrayList再次迭代其所有元素并执行" 123" .equals(element)以确定元素是否等于参数对象" 123"。它发现等于给定参数" 123"的第一个元素被删除。

如我们所见,.equals()的正确实现对于我们自己的类与Java Collection类一起正常工作至关重要。那么,如何"适当"地实现equals()呢?

那么,两个对象什么时候相等?这取决于应用程序,类以及我们要尝试执行的操作。例如,假设我们正在加载和处理存储在数据库中的"雇员"对象。这是一个这样的Employee类的简单示例:

public class Employee {
    protected long   employeeId;
    protected String firstName;
    protected String lastName;
}

我们可以决定两个" Employee"对象是否相等,只要它们的" employeeId"相等。或者,我们可以决定所有字段必须都等于" employeeId"," firstName"和" lastName"。这是匹配这些条件的equals()的两个示例实现:

public class Employee {
  ...
  public boolean equals(Object o){
    if(o == null)                return false;
    if(!(o instanceof) Employee) return false;

    Employee other = (Employee) o;
    return this.employeeId == other.employeeId;
  }
}
public class Employee {
  ...
  public boolean equals(Object o){
    if(o == null)                return false;
    if(!(o instanceof) Employee) return false;

    Employee other = (Employee) o;
    if(this.employeeId != other.employeeId)      return false;
    if(! this.firstName.equals(other.firstName)) return false;
    if(! this.lastName.equals(other.lastName))   return false;

    return true;
  }
}

这两个实现中的哪一个"合适"取决于我们需要执行的操作。有时我们需要从缓存中查找" Employee"对象。在这种情况下,我们可能需要的是使employeeId相等。在其他情况下,我们可能需要的还不止此,例如,确定" Employee"对象的副本是否已从原始对象更改。

hashCode()

当将对象插入到HashTable,HashMap或者HashSet中时,将使用对象的hashCode()方法。如果我们不了解哈希表在内部如何工作的理论,则可以在Wikipedia.org上阅读有关hastables的信息。

将对象插入hastable中时,可以使用键。计算该密钥的哈希码,并将其用于确定内部存储对象的位置。当我们需要在哈希表中查找对象时,我们还可以使用键。计算该密钥的哈希码,并将其用于确定在何处搜索对象。

哈希码仅在内部指向某个"区域"(或者列表,存储桶等)。由于不同的密钥对象可能具有相同的哈希码,因此哈希码本身不能保证找到正确的密钥。然后,哈希表会对该区域(所有具有相同哈希码的键)进行迭代,并使用键的" equals()"方法来找到正确的键。找到正确的键后,将返回为该键存储的对象。

因此,如我们所见,在存储和查找哈希表中的对象时,会使用hashCode()equals()方法的组合。

如果Java Collections API中的哈希表能够正常工作,那么以下两个关于在我们自己的类中实现hashCode()方法的知识非常有用:

  • 如果object1和object2根据其equals()方法相等,则它们还必须具有相同的哈希码。
  • 如果object1和object2具有相同的哈希码,则它们也不必相等。

简而言之:

  • 如果相等,则也使用相同的哈希码。
  • 相同的哈希码不能保证相等。

这是与前面显示的equals()方法匹配的hashCode()方法的两个示例实现:

public class Employee {
  protected long   employeeId;
  protected String firstName;
  protected String lastName;

  public int hashCode(){
    return (int) employeeId;
  }
}
public class Employee {
    protected long   employeeId;
    protected String firstName;
    protected String lastName;

  public int hashCode(){
    return (int) employeeId *
                firstName.hashCode() *
                lastName.hashCode();
  }
}

注意,如果两个" Employee"对象相等,则它们也将具有相同的哈希码。但是,正如在第一个示例中特别容易看到的那样,两个" Employee"对象可以不相等,并且仍具有相同的哈希码。

在两个示例中,哈希码都是将" employeeId"四舍五入为" int"。这意味着许多雇员ID可能导致相同的哈希码,但是这些"雇员"对象仍然不相等,因为它们没有相同的雇员ID。