2016 - 2024

感恩一路有你

Java中的equals和hashCode方法

浏览量:2170 时间:2024-01-25 18:13:11 作者:采采

引言

在Java中,、equals()和hashCode()都和对象的比较有关。但是为什么需要设计这三种对象的比较方法呢?本文将解释它们的用途。

操作符

操作符用于判断两个对象是否是同一个对象。对于引用变量而言,比较的是两个引用变量引用的是不是同一个对象,即比较的是两个引用中存储的对象地址是不是一样的。对于基本数据类型而言,比较的是两个数据是不是相等。由于基本数据类型没有方法,所以不存在equals()和hashCode()的问题,下面的讨论都是针对引用类型而言的。

equals()方法

为什么Java会设计equals()方法?操作符只能判断两个对象是否是同一个对象,这并不能满足很多需求。有时候当两个对象不是同一个对象的时候,我们仍然会认为两者是“相等”的,比如对于String对象,当两个对象的字符串序列是一致的,我们就认为他们是“相等”的。对于有这种需求的对象的类,需要重写其equals()方法来实现具体的“相等”逻辑。需要注意的是,Object类中的默认实现是比较两个对象是不是同一个对象,即其和操作符的效果是相同的。Java提供的某些类已经重写了equals()方法,自己编写的类如果需要实现自己的“相等”逻辑,也需要重写equals()方法。

hashCode()方法

为什么会设计hashCode()方法?hashCode()方法返回的是一个数值,我们称之为hashCode。从方法的名称上就可以看出,其目的是生成一个hash码。hash码的主要用途就是在对对象进行散列的时候作为key输入,所以每个对象的hash码尽可能不同,这样才能保证散列的存取性能。Object类提供的默认实现确保每个对象的hash码不同(在对象的内存地址基础上经过特定算法返回一个hash码)。根据Java规范,hashCode()方法和equals()方法可以没有关系。

equals()和hashCode()的关系

对于集合类HashSet、HashMap等和hash有关的类,是通过hash算法来散列对象的。对HashSet而言,存入对象的流程为:根据对象的hash码,经过hash算法,找到对象应该存放的位置,如果该位置为空,则将对象存入该位置;如果该位置不为空,则使用equals()比较该位置的对象和将要入的对象,如果两个相等,则不再插入,如果不相等,则根据hash冲突解决算法将对象插入其他位置。Java规定对于HashSet判断是不是重复对象就是通过equals()方法来完成,这就需要在两个对象equals()方法相等的时候,hash码一定相等(即hashCode()返回的值相等)。假设两个对象equals()方法相等的时候,hash码不相等,会出现equals()相等的两个对象都插入了HashSet中,这是不允许的。因此我们有以下结论:对于equals()相等的两个对象,其hashCode()返回的值一定相等。

如何设计hashCode()方法

为了保证“对于equals()相等的对象hashCode()要一定相等”,在设计hashCode()方法时,可以从对象的各个关键域中选取部分或全部字段,通过特定算法得到一个hash码。同样地,对于equals()不同的对象,应该尽量保证hash码不同。一个常用的算法如下:

1. 把某个非零常数值(一般取素数)17保存在int变量result中。

2. 对于对象中的每一个关键域f:

- 如果f是boolean型,计算(f ? 0 : 1)。

- 如果f是byte、char、short型,计算(int)f。

- 如果f是long型,计算(int) (f ^ (f >>> 32))。

- 如果f是float型,计算Float.floatToIntBits(afloat)。

- 如果f是double型,计算(adouble)得到一个long,再执行上一步。

- 如果f是对象引用,递归调用它的hashCode()方法。

- 如果f是数组域,对其中每个元素调用它的hashCode()方法。

3. 将上面计算得到的散列码保存到int变量c,然后执行result 37 * result c。

4. 返回result。

通过这种算法,可以保证“对于equals()相等的对象hashCode()返回的值一定相等”,并且尽可能使不同的对象产生不同的hash码。

通过以上分析,我们可以得出equals()和hashCode()在Java中的使用和设计原则。对于需要进行对象比较的类,应该重写equals()方法来实现自定义的“相等”逻辑,并同时重写hashCode()方法,以满足equals()和hashCode()的关联要求。这样可以确保在使用HashSet等集合类时,对象的比较和散列的正确性。

版权声明:本文内容由互联网用户自发贡献,本站不承担相关法律责任.如有侵权/违法内容,本站将立刻删除。