关于重写equals方法和hashCode方法

关于重写equals方法和hashCode方法

薛定谔的汪

写在前面的话:

  我之前写的动态博客 搜索功能实现时遇到了一个小问题,想保证数据库查询出来的同一笔数据是同一个对象,即如果两笔数据中包含相同的articleId(主键Id在表里是唯一的),那么就把这两笔数据作为同一个对象,这需要重写对象的equals方法和hashCode方法,具体代码如下:

equals方法和hashcode方法…

public boolean eqauls(Object obj)方法

  Object类中默认的实现方式是 : return this == obj 。那就是说,只有this 和 obj引用同一个对象,才会返回true。而我们往往需要用equals来判断 2个对象是否等价,而非验证他们的唯一性。这样我们在实现自己的类时,就要重写equals.
  按照约定,equals要满足以下规则。
自反性: x.equals(x) 一定是true
对null: x.equals(null) 一定是false
对称性: x.equals(y) 和 y.equals(x)结果一致
传递性: a 和 b equals , b 和 c equals,那么 a 和 c也一定equals。
一致性: 在某个运行时期间,2个对象的状态的改变不会不影响equals的决策结果,那么,在这个运行时期间,无论调用多少次equals,都返回相同的结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 class Test{
private int num;
private String data;
public boolean equals(Object obj)
{
if (this == obj)
return true;

if ((obj == null) || (obj.getClass() != this.getClass()))
return false;
//能执行到这里,说明obj和this同类且非null。
Test test = (Test) obj;
return num == test.num&& (data == test.data || (data != null && data.equals(test.data)));
}

public int hashCode()
{
//重写equals,也必须重写hashCode。具体后面介绍。
}
}

  Test类对象有2个字段,num和data,他们也用在equals方法中作为评判的依据。
在第8行,传入的比较对象的引用和this做比较,这样做是为了节约执行时间,如果this 和 obj是 对同一个堆对象的引用,那么,他们一定是qeuals 的。
接着,判断obj是不是为null,如果为null,一定不equals,因为既然当前对象this能调用equals方法,那么它一定不是null,非null 和 null当然不等价。 然后,比较2个对象的运行时类,是否为同一个类。不是同一个类,则不equals。getClass返回的是 this 和obj的运行时类的引用。如果他们属于同一个类,则返回的是同一个运行时类的引用。

public int hashCode()方法

  这个方法返回对象的散列码,返回值是int类型的散列码。
  关于hashCode方法,一致的约定是:

  • 重写了euqls方法的对象必须同时重写hashCode()方法。
  • 如果2个对象通过equals调用后返回是true,那么这个2个对象的hashCode方法也必须返回同样的int型散列码
  • 如果2个对象通过equals返回false,他们的hashCode返回的值允许相同。
  • 在上面的例子中,Test类对象有2个字段,num和data,这2个字段用在equals方法中作为评判的依据。那么, 在hashCode方法中,这2个字段也要参与hash值的运算,作为hash运算的中间参数。这点很关键,这是为了遵守:2个对象equals,那么 hashCode一定相同规则。
  • 也是说,参与equals函数的字段,也必须都参与hashCode 的计算。相比 于 equals公认实现约定,hashCode的公约要求是很容易理解的。有2个重点是hashCode方法必须遵守的。约定的第3点,其实就是第2点的细化,下面我们就来看看对hashCode方法的一致约定要求。

在某个运行时期间,只要对象的(字段的)变化不会影响equals方法的决策结果,那么,在这个期间,无论调用多少次hashCode,都必须返回同一个散码。
通过equals调用返回true 的2个对象的hashCode一定一样。
通过equasl返回false 的2个对象的散列码不需要不同,也就是他们的hashCode方法的返回值允许出现相同的情况。

总结:

equals相同,hashCode一定相同;equals不同,hashCode可以不同。
hashCode相同,equals不一定相同;hashCode不同equals一定不同。

  • Title: 关于重写equals方法和hashCode方法
  • Author: 薛定谔的汪
  • Created at : 2017-10-03 11:31:28
  • Updated at : 2023-11-17 19:37:37
  • Link: https://www.zhengyk.cn/2017/10/03/java/Eqha/
  • License: This work is licensed under CC BY-NC-SA 4.0.