在这篇文章中,我将概述我对方法覆盖
Apache Commons 提供了两个很棒的帮助器类来调用方法
hashCode()
和的理解equals()
。我想谈谈它们的默认实现,以及如何正确地覆盖它们。我还将撰写有关使用 Apache Common 包的帮助程序类实现这些方法的文章。 这篇文章的内容:
- 使用
hashCode()
和equals()
. - 覆盖默认行为。
- 覆盖
hashCode()
并equals()
使用 Apache Commons Lang。 - 需要记住的重要事情。
- 使用 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() ...它将为您生成一个非常好的实现。 需要记住的重要事情。
- 始终使用相同的对象属性来调用 and
hashCode()
和equals()
。就我们而言,我们使用了employee id
. - 该方法
equals()
必须是持久的(如果对象没有改变,该方法必须返回相同的值)。 - 无论何时
a.equals(b)
,那么a.hashCode()
一定是一样的b.hashCode()
。 - 如果重写一种方法,则必须重写第二个方法。
使用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 这是我第一次尝试翻译。我试图尽可能接近作者想要表达的内容。如果您有任何意见,请写在评论中。不要严格判断:-))) 原创文章
GO TO FULL VERSION