【翻译】玩转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.lang.Object的equals()和hashCode()方法小结
- java中的hashcode()和equals()方法详解
- java equals与hashCode 两个重要方法的重写
- JAVA中重写equals()方法为什么要重写hashcode()方法说明
- Java中的hashcode()和equals()方法详解
- Java中的equals方法与hashCode方法解析
- JAVA中的equals()和hashCode()方法(经典)
- java 重写类的equals方法和hashcode方法
- 一种常见的Java编程错误:没有同时定义equals()和hashCode()方法
- java中重写Object类的equals方法和Hashcode方法的注意事项
- 深入java 的equals方法和hashCode方法
- Java软件低级错误: 定义equals方法的同时也要定义hashCode方法
- java对象通用方法之覆盖equals时请遵守通用约定、覆盖equals时总要覆盖hashCode、始终要覆盖toString、考虑实现Comparable接口
- Java中的equals()和hashCode()方法
- Java Collection框架在Collection的生命周期中需要基于不变字段的equals()和hashCode()方法
- Java Class 中hashCode()和equals方法
- JAVA中重写equals()方法为什么要重写hashcode()方法说明
- Java中重写Object类的equals方法和 hashcode方法的注意事项
- Java中重写Object类的equals方法和hashcode方法的注意事项
- java.lang.Object的equals()和hashCode()方法小结