hashCode和equals方法的理解

来源:互联网 发布:mysql如何查看 编辑:程序博客网 时间:2024/05/17 18:41
这篇文章中,我将告诉大家我对hashCode和equals方法的理解。我将讨论他们的默认实现,以及如何正确的重写他们。我也将使用Apache Commons提供的工具包做一个实现。 

目录:

  1. hashCode()和equals()的用法
  2. 重写默认实现
  3. 使用Apache Commons Lang包重写hashCode()和equals()
  4. 需要注意记住的事情
  5. 当使用ORM的时候特别要注意的
hashCode()和equals()定义在Object类中,这个类是所有java类的基类,所以所有的java类都继承这两个方法。


使用hashCode()和equals()

hashCode()方法被用来获取给定对象的唯一整数。这个整数被用来确定对象被存储在HashTable类似的结构中的位置。默认的,Object类的hashCode()方法返回这个对象存储的内存地址的编号。

重写默认的实现

如果你不重写这两个方法,将几乎不遇到任何问题,但是有的时候程序要求我们必须改变一些对象的默认实现。

来看看这个例子,让我们创建一个简单的类Employee

01public class Employee
02{
03    private Integer id;
04    private String firstname;
05    private String lastName;
06    private String department;
07 
08    public Integer getId() {
09        return id;
10    }
11    public void setId(Integer id) {
12        this.id = id;
13    }
14    public String getFirstname() {
15        return firstname;
16    }
17    public void setFirstname(String firstname) {
18        this.firstname = firstname;
19    }
20    public String getLastName() {
21        return lastName;
22    }
23    public void setLastName(String lastName) {
24        this.lastName = lastName;
25    }
26    public String getDepartment() {
27        return department;
28    }
29    public void setDepartment(String department) {
30        this.department = department;
31    }
32}
上面的Employee类只是有一些非常基础的属性和getter、setter.现在来考虑一个你需要比较两个employee的情形。


01public class EqualsTest {
02    public static void main(String[] args) {
03        Employee e1 = new Employee();
04        Employee e2 = new Employee();
05 
06        e1.setId(100);
07        e2.setId(100);
08        //Prints false in console
09        System.out.println(e1.equals(e2));
10    }
11}
毫无疑问,上面的程序将输出false,但是,事实上上面两个对象代表的是通过一个employee。真正的商业逻辑希望我们返回true。 
为了达到这个目的,我们需要重写equals方法。 
01public boolean equals(Object o) {
02        if(o == null)
03        {
04            return false;
05        }
06        if (o == this)
07        {
08           return true;
09        }
10        if (getClass() != o.getClass())
11        {
12            return false;
13        }
14        Employee e = (Employee) o;
15        return (this.getId() == e.getId());
16}
在上面的类中添加这个方法,EauqlsTest将会输出true。 
So are we done?没有,让我们换一种测试方法来看看。 
01import java.util.HashSet;
02import java.util.Set;
03 
04public class EqualsTest
05{
06    public static void main(String[] args)
07    {
08        Employee e1 = new Employee();
09        Employee e2 = new Employee();
10 
11        e1.setId(100);
12        e2.setId(100);
13 
14        //Prints 'true'
15        System.out.println(e1.equals(e2));
16 
17        Set<Employee> employees = new HashSet<Employee>();
18        employees.add(e1);
19        employees.add(e2);
20        //Prints two objects
21        System.out.println(employees);
22    }
上面的程序输出的结果是两个。如果两个employee对象equals返回true,Set中应该只存储一个对象才对,问题在哪里呢? 
我们忘掉了第二个重要的方法hashCode()。就像JDK的Javadoc中所说的一样,如果重写equals()方法必须要重写hashCode()方法。我们加上下面这个方法,程序将执行正确。
1@Override
2 public int hashCode()
3 {
4    final int PRIME = 31;
5    int result = 1;
6    result = PRIME * result + getId();
7    return result;
8 }
使用Apache Commons Lang包重写hashCode() 和equals()方法 
Apache Commons 包提供了两个非常优秀的类来生成hashCode()和equals()方法。看下面的程序。 


01import org.apache.commons.lang3.builder.EqualsBuilder;
02import org.apache.commons.lang3.builder.HashCodeBuilder;
03public class Employee
04{
05 private Integer id;
06 private String firstname;
07 private String lastName;
08 private String department;
09public Integer getId() {
10    return id;
11 }
12 public void setId(Integer id) {
13    this.id = id;
14 }
15 public String getFirstname() {
16    return firstname;
17 }
18 public void setFirstname(String firstname) {
19    this.firstname = firstname;
20 }
21 public String getLastName() {
22    return lastName;
23 }
24 public void setLastName(String lastName) {
25    this.lastName = lastName;
26 }
27 public String getDepartment() {
28    return department;
29 }
30 public void setDepartment(String department) {
31    this.department = department;
32 }
33@Override
34 public int hashCode()
35 {
36    final int PRIME = 31;
37    return new HashCodeBuilder(getId()%2==0?getId()+1:getId(), PRIME).
38           toHashCode();
39 }
40@Override
41 public boolean equals(Object o) {
42    if (o == null)
43       return false;
44    if (o == this)
45       return true;
46    if (o.getClass() != getClass())
47       return false;
48    Employee e = (Employee) o;
49       return new EqualsBuilder().
50              append(getId(), e.getId()).
51              isEquals();
52    }
53 }
如果你使用Eclipse或者其他的IDE,IDE也可能会提供生成良好的hashCode()方法和equals()方法。 

需要注意记住的事情

  • 尽量保证使用对象的同一个属性来生成hashCode()和equals()两个方法。在我们的案例中,我们使用员工id。
  • eqauls方法必须保证一致(如果对象没有被修改,equals应该返回相同的值)
  • 任何时候只要a.equals(b),那么a.hashCode()必须和b.hashCode()相等。
  • 两者必须同时重写。
当使用ORM的时候特别要注意的
  • 如果你使用ORM处理一些对象的话,你要确保在hashCode()和equals()对象中使用getter和setter而不是直接引用成员变量。因为在ORM中有的时候成员变量会被延时加载,这些变量只有当getter方法被调用的时候才真正可用。
  • 例如在我们的例子中,如果我们使用e1.id == e2.id则可能会出现这个问题,但是我们使用e1.getId() == e2.getId()就不会出现这个问题。
希望这篇文章能够帮助你。


原文链接/OSCHINA翻译

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 实习手册没有公司的印章怎么办? 家长管的太严怎么办 对于老公沉迷于股票怎么办 月经期吃了香瓜怎么办 月经漏到内裤上怎么办 上班没时间养狗怎么办 宝宝呼吸道感染反复发烧怎么办 熬夜后头晕想吐怎么办 生气后全身无力酸痛怎么办? 久坐导致的腰疼怎么办 削土豆手变黑了怎么办 熬夜后头痛眼痛怎么办 孩子毎天通宵游戏怎么办 熬夜写作业困了怎么办 三十多岁白头发越来越多怎么办 AI界面字体太小怎么办 睡不着怎么办躺倒床上脑子混乱 作息规律不正常夜里睡不着怎么办 作息不规律引起身体痒怎么办 在大学里好无聊怎么办 开会时间通知错了怎么办 商场要求商户变更位置怎么办 怀孕初期症状小腹痛怎么办 1岁半宝宝吃夜奶怎么办 戒奶宝宝不喝奶粉怎么办 2岁半宝宝老晚睡怎么办 老是熬夜然后想调生物钟怎么办 一个月宝宝睡眠不好怎么办 个人怎么办一清pos机 社保到退休年龄未交满15年怎么办 退休时社保没交满15时怎么办 单位不支付病假工资怎么办 一年级学生上课注意力不集中怎么办 一年级学生的理解能力差怎么办 一年级学生学习太差怎么办 宝宝屁眼破皮怎么办啊 九个月婴儿不爱喝奶怎么办 十一个月婴儿发烧怎么办 四个月宝宝睡不踏实怎么办 5个月宝宝瘦了怎么办 宝宝只吃迷糊奶怎么办