使用hashCode()和equals()方法 - Java
在这篇文章中,我将指出我对hashCode()和equals()方法的理解。我将讨论它们的默认实现以及如何正确地覆盖它们。我还将使用Apache Commons包中的实用工具类来实现这些方法。
hashCode()和equals()方法已经在Object类中定义,而Object类是所有Java对象的父类。因为这个原因,所有的Java对象从Object类继承了这些方法的默认实现。
本文中的章节:
hashCode()和equals()用法
重写默认行为
用Apache Commons Lang重写equals()和hashCode()
需要记住的重要的事项
在ORM中使用时要注意的地方
hashCode()和equals()方法的用法
hashCode()方法用于获取给定对象的唯一的整数。当这个对象需要存储在哈希表这样的数据结构时,这个整数用于确定桶的位置。默认情况下,对象的hashCode()方法返回对象所在内存地址的整数表示。
equals()方法用来简单验证两个对象的相等性。默认实现只检查两个对象的对象引用,以验证它们的相等性。
重写默认行为
通常情况下,类一切运行的都很好,根本不需要重写它们,但是有时应用程序需要更改某些对象的默认行为。
让我们举一个例子,比如有一个应用程序拥有员工对象。让我们创建一个尽可能简单的员工类:
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;
}
}
上面的员工类有一些非常基本的属性和访问方法。现在考虑一个简单的情况,您需要比较两个员工对象。
public class EqualsTest {
public static void main(String[] args) {
Employee e1 = new Employee();
Employee e2 = new Employee();
e1.setId(100);
e2.setId(100);
//Prints false in console
System.out.println(e1.equals(e2));
}
}
不用猜,以上方法将输出“false”。但是,这两个对象现实生活中代表同一雇员。在实际应用程序中,必须返回true。
要实现正确的行为,我们需要如下重载equal方法:
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());
}
把这个方法添加到你的员工,开始运行EqualTest,将打印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); //Prints 'true'
System.out.println(e1.equals(e2)); Set<Employee> employees = new HashSet<Employee>();
employees.add(e1);
employees.add(e2); //Prints two objects
System.out.println(employees);
}
}
上面的类在第二个打印语句中打印两个对象。如果员工对象已经相等,在一个Set集合中应该只存在一个对象, HashSet中该只有一个实例才对,毕竟对象指的是同一名员工。哪里出现了问题??
问题出现在我们没有重写第二个重要的方法hashCode()。Java文档说,如果重写equals()方法,然后你必须重写hashCode()方法。因此,让我们在员工类中添加另一个方法。
@Override
public int hashCode()
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId();
return result;
}
一旦在雇员类中添加了上述方法,第二个语句就开始在第二个语句中只打印单个对象,从而验证了e1和e2的真正相等性。
用Apache Commons Lang 重写equals()和hashCode()
Apache Commons提供两个优秀的实用类 HashCodeBuilder和EqualsBuilder用于生成hashCode和测试相等性的代码。下面是它们的使用:
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选项, 在类上右键 >> source > Generate hashCode() and equals() … 会为你生成一个很好的实现。

需要记住的重要事项
1) 始终使用一个对象的相同属性来生成hashCode()和equals()方法。在我们的例子中,我们使用了员工id。
2) equals()必须一致(如果对象不被修改,那么它必须返回相同的值)。
3) 每当a.equals(b),那么a.hashCode()和b. hashCode()必须相等。
4) 如果重写一个,则应重写另一个。
ORM中使用时需要注意的地方
如果你正在处理一个ORM,确保hashCode()和equals()中始终使用getters,不要直接使用字段。这是因为在ORM中,偶尔字段被延迟加载,直到调用它们的getter方法时才可用。
例如我们的员工类,如果我们使用e1.id = = e2.id。id字段非常可能是懒加载。因此,在这种情况下,一个可能是零或null,从而导致不正确的行为。
但如果采用e1.getid() == e2.getid(),我们可以肯定,即使是懒加载,调用getter将首先让字段加载正确。
这就是我关于hashCode()和equals()方法所知道的,希望它会帮助有的人。
如果你觉得,我遗漏了什么或错误的地方,请留下评论。我会再次更新这篇文章来帮助别人。
Happy Learning !!
使用hashCode()和equals()方法 - Java的更多相关文章
- Java 中正确使用 hashCode 和 equals 方法
在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...
- K:java中的hashCode和equals方法
hashCode和equals方法是Object类的相关方法,而所有的类都是直接或间接的继承于Object类而存在的,为此,所有的类中都存在着hashCode和equals.通过翻看Object类 ...
- (转)Java 中正确使用 hashCode 和 equals 方法
背景:最近在编写持久化对象时候遇到重写equals和hashCode方法的情况,对这两个方法的重写做一个总结. 链接:https://www.oschina.net/question/82993_75 ...
- 重写Java Object对象的hashCode和equals方法实现集合元素按内容判重
Java API提供的集合框架中Set接口下的集合对象默认是不能存储重复对象的,这里的重复判定是按照对象实例句柄的地址来判定的,地址相同则判定为重复,地址不同不管内容如何都判定为不重复,这有时与需求不 ...
- 关于java中的hashcode和equals方法原理
关于java中的hashcode和equals方法原理 1.介绍 java编程思想和很多资料都会对自定义javabean要求必须重写hashcode和equals方法,但并没有清晰给出为何重写此两个方 ...
- Java中Set的contains()方法——hashCode与equals方法的约定及重写原则
转自:http://blog.csdn.net/renfufei/article/details/14163329 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashC ...
- Java中正确使用hashCode和equals方法
在这篇文章中,我将告诉大家我对hashCode和equals方法的理解.我将讨论他们的默认实现,以及如何正确的重写他们.我也将使用Apache Commons提供的工具包做一个实现. 目录: hash ...
- Java 重写 hashCode() 和 equals() 方法
1. hashCode 1.1 基本概念 hashCode 是 JDK 根据对象的地址算出来的一个 int 数字(对象的哈希码值),代表了该对象再内存中的存储位置. hashCode() 方法是超级类 ...
- 为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。
我在面试 Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候选人直接说没写过.我就想,或许真的没写过,于是就再通过一个问题确认:你在用HashMap的时候,键(Key)部分, ...
随机推荐
- MongoDB副本集的常用操作及原理
本文是对MongoDB副本集常用操作的一个汇总,同时也穿插着介绍了操作背后的原理及注意点. 结合之前的文章:MongoDB副本集的搭建,大家可以在较短的时间内熟悉MongoDB的搭建和管理. 下面的操 ...
- 【Netty】第一个Netty应用
一.前言 前面已经学习完了Java NIO的内容,接着来学习Netty,本篇将通过一个简单的应用来了解Netty的使用. 二.Netty应用 2.1 服务端客户端框架图 下图展示了Netty中服务端与 ...
- 欲练JS,必先攻CSS——前端修行之路(码易直播)
以下是直播大概内容的文字版: 感谢大家今天来到直播间收听本期的码易直播.今天我讲的主题是css,具体聊一下我大概的css学习历史,分享一些干货,希望这次分享对大家有所启发和帮助. 个人的css历史: ...
- Git详细教程---多人协作开发
Git可以完成两件事情: 1. 版本控制 2.多人协作开发 如今的项目,规模越来越大,功能越来越多,需要有一个团队进行开发. 如果有多个开发人员共同开发一个项目,如何进行协作的呢. Git提供了一个非 ...
- JS执行效率与性能提升方案
如果是追加字符串,最好使用s+=anotherStr操作,而不是要使用s=s+anotherStr.如果要连接多个字符串,应该少使用+=,如 s+=a;s+=b;s+=c;应该写成s+=a + b + ...
- Unity C# 一些关于Camera的心得!
本文原创,转载请注明出处:http://www.cnblogs.com/AdvancePikachu/p/6856374.html 首先,总结了下最近工作中关于摄像机漫游的功能, 脚本如下: Tran ...
- JDK版本会影响项目部署
最近在公司里面部署javaweb项目的时候,项目启动的时候报错,我使用了各种方法来寻找答案,将近花了很长的时间.就在今天我终于找到了问题的根源,我开始用的是JDK1.8的版本,换了一个1.7版本的JD ...
- 一个小博客教你把vim用飞起来
引言 今天我们特地来讲讲这个vim的配置. vim这东西, 很多人装逼的时候经常会提到, 不过大部分人对个vim的配置还是很陌生的, 因为 这个编辑器的学习成本还是有点高的, 但是不要紧, 今天我们就 ...
- 点击Input框弹出日期选项
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Java编程之委托代理回调、内部类以及匿名内部类回调(闭包回调)
最近一直在看Java的相关东西,因为我们在iOS开发是,无论是Objective-C还是Swift中,经常会用到委托代理回调,以及Block回调或者说是闭包回调.接下来我们就来看看Java语言中是如何 ...