当前位置: 首页 > 科技观察

为什么重写Equals方法通常要重写Hashcode方法?

时间:2023-03-15 00:25:47 科技观察

本文转载自微信公众号《程序新视野》,作者为二哥。转载本文请联系程序新视界公众号。最近面试的时候,在问到HashMap的数据结构之后,通常还会问到一个问题,那就是:为什么在重写equals方法的时候,一般都会重写hashcode方法?其实这道题本质上又回到了HashMap,只是想看看面试者是否真的了解应用场景。今天的文章就带大家了解一下equals方法和hashcode方法的关系,以及相关的知识点。equals和hashcode的存在其实每个类都有equals方法和hashcode方法。因为所有的类都继承自Object类。Object类中的定义如下:publicbooleanequals(Objectobj){return(this==obj);}publicnativeinthashCode();直观上可以看出equals方法默认比较对象引用,直接使用“==”进行比较。hashCode方法是一个native方法,返回值是一个整数。而且这两个方法都没有被final修改,都可以重写。对于我们经常使用的类,如String、Math、Integer、Double等,重写了equals()和hashCode()方法。equals()方法equals()方法用于判断两个对象是否相等。Object默认实现了equals方法,但显然不适合个人需求,所以经常需要重写。比如常用的String类,重写equals方法如下://重写equals方法publicbooleanequals(ObjectanObject){if(this==anObject){returntrue;}if(anObjectinstanceofString){StringanotherString=(String)anObject;intn=value.length;if(n==anotherString.value.length){charv1[]=value;charv2[]=anotherString.value;inti=0;while(n--!=0){if(v1[i]!=v2[i])returnfalse;i++;}returntrue;}}returnfalse;}这里的比较不再是简单的地址比较。首先按地址比较,如果地址相同则一定是同一个对象。如果地址不同,则比较char数组的内容,完全相等则返回true。equals()方法的特性在Object类的equals方法上进行了注释,以说明equals()方法需要满足的一些特性:Reflexive(自反)。对于任何非空的参考值x,x.equals(x)必须为真;对称的。对于任何非空引用值x和y,当且仅当x.equals(y)为真时y.equals(x)为真;传递的。对于任意非空引用值x、y、z,如果x.equals(y)为真且y.equals(z)为真,则x.equals(z)必为真;一致性(consistent)。对于任何非空引用值x和y,如果用于equals比较的对象信息没有被修改,x.equals(y)在多次调用时要么一致返回true,要么一致返回false;对于任何非null的null的引用值x,x.equals(null)返回false;对比以上特点,我们发现Object方法直接比较两个引用地址,只有两个地址相同才能相等,也就是说最有可能不同。价格关系。String的equals方法不仅包括申请地址相同的情况,还包括其中存储的字符串值相同的情况。也就是说,虽然有两个String对象,但是它们的字符串值是相等的,那么equals方法返回的结果为真。在大多数情况下,这正是我们所说的“equals方法比较值”的意思。由于存在Object的equals方法的默认特例,在没有自定义equals方法的情况下,我们不能说equals方法比较的是具体的值,而“==”比较的是引用。hashCode()方法hashCode()方法返回对象的散列码值。该方法用于哈希表,如HashSet、HashMap。hashCode()是一个native方法,返回值类型是integer,可以重写。Object中原生的hashCode()方法以哈希码的形式返回对象在内存中的地址,保证不同的对象返回不同的值。同样以String类为例,其hashCode方法为://重写hashCode方法publicinthashCode(){inth=hash;if(h==0&&value.length>0){charval[]=value;for(inti=0;i>>32))(4)如果是float值,计算Float.floatToIntBits(f)(5)如果是double值,则计算Double.doubleToLongBits(f),返回结果为long,再用规则(3)处理longtogetint(6)如果是对象应用,如果equals方法采用递归比较的方式,那么在hashCode中,也采用递归调用hashCode的方式。否则需要对这个字段计算一个正常的形式,比如当这个字段的值为null时,那么hashCode值为0(7)如果是数组,那么每个元素都需要单独处理场地。java.util.Arrays.hashCode方法包括8种基本类型数组和引用数组的hashCode计算,算法同上。C、最后将各个字段的哈希码合并到对象的哈希码中。小结很清楚equals方法是用来比较两个对象是否相等的。hashCode方法的重点是在类似HashMap的场景下提升效率,只是技术需求。在集合中,通常使用equals方法比较对象是否相等,hashCode方法用于解决数据量大时会出现的性能问题。实际中我们很少使用Object对象作为Map的key,因为如果Object对象的属性发生变化,hashCode也会发生变化,可能找不到对应的值,而String是不可变对象,作为key它恰到好处。参考文章:https://www.cnblogs.com/kismetv/p/7191736.htmlhttps://www.iteye.com/blog/kakajw-935226https://www.iteye.com/blog/bijian1013-1972404