您的位置:首页 > 编程语言 > Java开发

【翻译】玩转Java的hashCode()与equals()方法

2016-08-23 10:50 309 查看

【翻译】玩转Java的
hashCode()
equals()
方法

原文地址:Working with hashCode and equals methods in java

本文将讨论Java中的
hashCode()
eqauls()
方法的默认实现,如何正确地重写,以及如何使用
Apache Commons
包的一些工具类。
hashCode()
eqauls()
方法在
Object
类中定义的,因此,所有的Java对象继承了这两个方法的默认实现。

一、
hashCode()
eqauls()
方法的使用

hashCode()
方法用来获取给定对象的特定整型值(哈希码)。在像
HashMap
类似的数据结果中,这个整数用来确定对象存储在哪个哈希桶(Hash bucket)中。默认情况下,对象的
hashCode()
方法返回的这个整型值代表了对象存储的内存地址。

equals()
方法用来判断两个对象是否相等。默认的实现仅简单地检查两个对象的引用地址是否相等。

二、重写默认的行为

如果我们在自定义的类中不重写任何方法,可以确保所有的方法运行正常。但是,在应用软件中经常需要去改变一些对象的默认行为。让我们来看一个包括
Employee
类的代码实例。首先,让我们来创建一个
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);

System.out.println(e1.equals(e2));
}
}


上述代码将返回“false”。但是从实际情况来看,这两个对象代表的其实是同一个employee,因此,在我们的应用中应该返回true

为了实现上述的行为,我们需要按如下的方式重写
equals()
方法:

@Override
public boolean equals(Object o) {
if(o == null){
return false;
}

if(o == this){
return true;
}

if(o instanceof Employee){
Employee e = (Employee) o;
return (this.getId() == e.getId());
}
return false;
}

@Override
public String toString() {
// TODO Auto-generated method stub
return "Employee:[id: "+this.getId() + "]";
}


将上述方法添加到
Employee
类后,
EqualsTest
将返回true

到此,我们就完成了所有工作了吗?当然不是。让我们用不同的方法来对测试一下修改后的
Employee
类。

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

e1.setId(100);
e2.setId(100);
//Prints 'true'
System.out.println(e1.equals(e2));

Set<Employee> employees = new HashSet<>();
employees.add(e1);
employees.add(e2);
//Prints two objects.
System.out.println(employees);
}
}


输出结果:

true
[Employee:[id: 100], Employee:[id: 100]]


上述代码打印
HashSet
对象
employees
时打印了两个。如果两个
employees
对象相等,那么
Set
中应该只保存一个对象。什么地方出错了呢?

我们还需要重写另一个重要的方法
hashCode()
。如Java Docs中所描述的,如果我们重写
equals()
方法,那么我们必须同时重写
hashCode()
方法。因此,让我们在
Employee
类中添加另一个方法。

@Override
public int hashCode() {
// TODO Auto-generated method stub
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId().hashCode();
return result;
}


执行
EqualsTest
,输出结果:

true
[Employee:[id: 100]]


当我们在
Employee
类中添加了上述方法,
EqualsTest````HashSet
对象
employees
时仅打印了一个对象,从而证明e1与e2相等性。

三、使用
Apache Commons Lang
重写
hashCode()
equals()
方法

Apache Commons
提供了两个非常优化的工具类
HashCodeBuilder
EqualsBuilder
,用来生成
hashCode()
equals()
方法。下面是其使用方法:

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.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 boolean equals(Object o) {
if(o == null){
return false;
}

if(o == this){
return true;
}

if(o instanceof Employee){
Employee e = (Employee) o;
return new EqualsBuilder().append(getId(), e.getId()).isEquals();
}
return false;
}

@Override
public int hashCode() {
final int PRIME = 31;
return new HashCodeBuilder(getId() % 2 == 0 ? getId() + 1 : getId(), PRIME).toHashCode();
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Employee:[id: "+this.getId() + "]";
}
}


此外,如果我们使用集成开发环境(IDE),我们也可以利用IDE来自动生成一个结构良好的代码。例如:在Eclipse IDE中可以右击**class>>source>>Generate hashCode() and equals()…,就可以为我们生成实现良好的代码。

四、需要记住的关键点

通常需要使用同一个属性来生成
hashCode()
equals()
方法。在上面的示例中,我们使用的是
Employee id


需要保证
equals()
方法返回值的一致性。即,如果对象没有被修改,那么,多次调用
equals()
方法比较时返回同样的值。

a.equals(b)
返回
true
时,
a.hashCode()
b.hashCode()
必须相等。

如果我们重写了
equals()
hashCode()
两个方法中的任意一个,则必须重写另一个。

五、在
ORM
中使用的特殊点

**Info: **ORM,Object Relation Mapping,对象关系映射,用于实现面向对象编程语言里不同类型系统的数据之间的转换。

我们在处理对象关系映射时,在
hashCode()
equals()
方法中需要确保访问对象属性时使用
getters
,而不是使用属性引用。因为,在对象关系映射的处理中,有时会使用迟延加载来实例化属性,对象属性直到调用
getter
方法时才可用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java hashcode equals