JavaRush /Java 博客 /Random-ZH /在 Java 中使用 hashCode() 和 equals() 方法
Lenchik854
第 0 级
Chernihiv

在 Java 中使用 hashCode() 和 equals() 方法

已在 Random-ZH 群组中发布
在这篇文章中,我将概述我对方法hashCode()和的理解equals()。我想谈谈它们的默认实现,以及如何正确地覆盖它们。我还将撰写有关使用 Apache Common 包的帮助程序类实现这些方法的文章。 在 Java 中使用 hashCode() 和 equals() 方法 - 1这篇文章的内容:
  1. 使用hashCode()equals().
  2. 覆盖默认行为。
  3. 覆盖hashCode()equals()使用 Apache Commons Lang。
  4. 需要记住的重要事情。
  5. 使用 ORM 时要特别注意。
hashCode()和方法equals()在 class 中定义Object,该类是 java 对象的父类。因此,所有java对象都继承了这些方法的默认实现。

使用 hashCode() 和 equals()

该方法hashCode()用于获取给定对象的唯一整数。当对象需要作为数据结构存储在哈希表(也称为存储桶)中时,该数字用于确定其在该表中的位置。默认情况下,对象的方法hashCode()返回存储该对象的内存位置的编号。equals()顾名思义,该方法用于简单地检查两个对象的相等性。此方法的默认实现只是检查两个对象的引用以查看它们是否等效。

覆盖默认行为

只要您不重写类中的任何这些方法,一切都会正常工作。但有时应用程序需要更改某些对象的默认行为。让我们举一个例子,其中您有一个Employee. 让我们编写这样一个类的最小可能结构。
public class Employee
{
    private Integer id;
    private String firstname;
    private String lastName;
    private String department;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getFirstname() {
        return firstname;
    }
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getDepartment() {
        return department;
    }
    public void setDepartment(String department) {
        this.department = department;
    }
}
上面描述的类Employee有一些基本属性和访问器方法。现在让我们看一个简单的情况,我们需要比较类的两个对象Employee
public class EqualsTest {
    public static void main(String[] args) {
        Employee e1 = new Employee();
        Employee e2 = new Employee();

        e1.setId(100);
        e2.setId(100);
        //Печатает false в консоли
        System.out.println(e1.equals(e2));
    }
}
不需要有洞察力就能猜到上面写的方法将返回“false”。但考虑到这两个对象是相同的,这实际上是正确的吗?在实时应用中,该方法必须返回true。为了实现正确的行为,我们需要重写该方法equals(),如下所示:
public boolean equals(Object o) {
        if(o == null)
        {
            return false;
        }
        if (o == this)
        {
           return true;
        }
        if (getClass() != o.getClass())
        {
            return false;
        }
        Employee e = (Employee) o;
        return (this.getId() == e.getId());
}
将此方法添加到您的类中Employee,等效性检查将返回“true”。然而,我们已经做到了一切吗?还没有。让我们用另一种方式测试修改后的类。
import java.util.HashSet;
import java.util.Set;

public class EqualsTest
{
    public static void main(String[] args)
    {
        Employee e1 = new Employee();
        Employee e2 = new Employee();

        e1.setId(100);
        e2.setId(100);

        //Печатает 'true'
        System.out.println(e1.equals(e2));

        Set employees = new HashSet();
        employees.add(e1);
        employees.add(e2);
        //Печатает два an object
        System.out.println(employees);
    }
}
该命令System.out.println(employee)打印两个对象。如果两个对象是等价的,并且Set只包含唯一的对象,那么HashSet里面应该只有一个实例,即 两个对象都引用该类的相同实例Employee。我们错过了什么?我们错过了第二个重要的方法hashCode()。正如java文档所说,如果你重写了方法equals(),那么你就需要重写该方法hashCode()。因此,让我们向我们的类添加另一个方法Employee
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + getId();
    return result;
 }
我们将此方法添加到我们的类中一次,并且只会打印一个对象,因此,检查 e1 和 e2 的等价性显示 true。

覆盖hashCode()equals()使用 Apache Commons Lang

Apache Commons 提供了两个很棒的帮助器类来调用方法hashCode()equals(). 下面我们看看用法:
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Employee
{
 private Integer id;
 private String firstname;
 private String lastName;
 private String department;
public Integer getId() {
    return id;
 }
 public void setId(Integer id) {
    this.id = id;
 }
 public String getFirstname() {
    return firstname;
 }
 public void setFirstname(String firstname) {
    this.firstname = firstname;
 }
 public String getLastName() {
    return lastName;
 }
 public void setLastName(String lastName) {
    this.lastName = lastName;
 }
 public String getDepartment() {
    return department;
 }
 public void setDepartment(String department) {
    this.department = department;
 }
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    return new HashCodeBuilder(getId()%2==0?getId()+1:getId(), PRIME).
           toHashCode();
 }
@Override
 public boolean equals(Object o) {
    if (o == null)
       return false;
    if (o == this)
       return true;
    if (o.getClass() != getClass())
       return false;
    Employee e = (Employee) o;
       return new EqualsBuilder().
              append(getId(), e.getId()).
              isEquals();
    }
 }
另一方面,如果您使用其中一个代码编辑器,它们也应该能够为您调用一些不错的结构。例如,如果在 Eclipse IDE 中右键单击类 >> 源 > 生成 hashCode() 和 equals() ...它将为您生成一个非常好的实现。 在 Java 中使用 hashCode() 和 equals() 方法 - 2需要记住的重要事情。
  1. 始终使用相同的对象属性来调用 andhashCode()equals()。就我们而言,我们使用了employee id.
  2. 该方法equals()必须是持久的(如果对象没有改变,该方法必须返回相同的值)。
  3. 无论何时a.equals(b),那么a.hashCode()一定是一样的b.hashCode()
  4. 如果重写一种方法,则必须重写第二个方法。

使用ORM时的特别注意

如果您正在处理 ORM (ru.wikipedia.org/wiki/ORM),那么请始终使用 getters 并且永远不要使用字段引用hashCode()equals()这是因为在 ORM 中,字段有时会使用延迟加载进行加载,并且在调用其 getter 之前无法访问。例如,在我们的班级中Employee,我们使用e1.id == e2.id. d 字段完全有可能是i使用延迟加载来加载的。其中一个字段可能为 0 或 null,我们将得到不正确的行为。但是,如果使用e1.getId() == e2.getId(),我们可以确定即使字段是使用延迟加载加载的;调用 getter 将首先填充该字段。hashCode()这就是我对和方法的全部了解equals()。希望这对某个地方的人有帮助。祝你学业顺利!!ps 这是我第一次尝试翻译。我试图尽可能接近作者想要表达的内容。如果您有任何意见,请写在评论中。不要严格判断:-))) 原创文章
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION