Hash和hashCode

一、Hash简介

       什么是Hash?音译成中文就是散列的意思。就是把任意长度的输入,通过散列算法变换成固定长度的输出,该输出就是散列值。这里有一个值得注意的地方,那就是输入不同经过Hash函数可能相同的Hash值(碰撞);如果两个Hash值不同,那么这两个Hash值对应的原始输入必不同。

二、equals()和hashcode()方法

       JDK中对equals(Object obj)和hashcode()这两个方法的定义和规范是:Java中任何一个对象都具有这两个方法,因为它们是在Object类中定义的。equals(Object obj)方法用来判断两个对象是否“相同”,如果“相同”则返回true,否则返回false;Java默认的实现是若两个对象指向同一内存地址则认为相同,否则认为不同。 hashCode()方法返回一个int数,在Object类中的默认实现是“将该对象的内部地址转换成一个整数返回”。

       在Java中,HashSet是基于HashMap底层实现的一个集合,它具有快速存取的特征。当集合要添加新的对象时,先调用这个对象的 hashCode方法,得到对应的hashcode值。实际上在HashMap的具体实现中会用一个table保存已经存进去的对象的hashcode 值,如果table中没有该hashcode值,它就可以直接存进去,不用再进行任何比较了;如果存在该hashcode值, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址,所以这里存在前面提到的“冲突”问题。这样一来实际调用 equals方法的次数就大大降低了。说通俗一点:Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的 字段等)映射成一个数值(通过调用hashCode方法获得),这个数值称作为散列值。

      equals和hashCode这两个方法的归纳总结如下:

       1.若重写了equals(Object obj)方法,则有必要重写hashCode()方法;

       2.若两个对象equals(Object obj)返回true,则hashCode()也要返回相同的int数;

       3.若两个对象equals(Object obj)返回false,则hashCode()不一定返回不同的int数;

       4.若两个对象hashCode()返回相同int数,则equals(Object obj)不一定返回true;

       5.若两个对象hashCode()返回不同int数,则equals(Object obj)一定返回false;

       6.同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。


三、什么时候重写equals()和hashCode()

       一般来说涉及到对象存储就要重写equals()方法,基本原则是只要重写了equals()就要重写hashCode()。为什么要这样?首先看一下一个对象放入HashSet的流程图:


如果重写了equals()但没有重写hashCode(),就有可能出现这样一种情况:有两个不同的对象,它们的所有字段值均相等,这时equals()判断两个对象相等。但是由于此时hashCode()还是默认的hashCode(),它们地址不同,所以它们的hashCode()不同。这样会带来什么影响?简单地说,两个Point类对象p1,p2都为(1,1),依次把它们添加到同一个HashSet中,它们由于hashcode()不同都会添加成功。但是这违背了HashSet集合中不可重复性这一原则。

       所以综上所述,若一个自定义的类重写了equals(),一定要记得重写hashCode()。


四、怎么重写equals()和hashCode()

       在自定义类中重写equals()的原则一般是:首先判断两个对象是不是同一类的对象,如果不是直接返回false;这里要注意一下:

if((obj == null) || (obj.getClass() != this.getClass())) 
   
     return false;   //应该这么写


if(!(obj instanceof Test)) 
    
     return false; // 避免这么写

因为 :
dog instanceof Animal 得true;
animal instanceof Dog 得false;
这样就可能出现:
animal.equals(dog)得true;
dog.equals(animal)得false。

然后判断两个对象的所有字段,如果两个对象的所有字段均相等,则认为equals()返回true,否则返回false。

       再看看hashCode()的重写原则,上面提到如果2个对象通过equals调用后返回是true,那么这个2个对象的hashCode方法也必须返回同样的int型散列码;如果2个对象通过equals返回false,他们的hashCode返回的值允许相同。所以说,参与equals函数的字段,也必须都参与hashCode 的计算。然后程序员根据自己选择的散列函数重写hashCode()方法。常见的重写方法是:

int hash = 7;

hash = 31 * hash + 字段1贡献分量;

hash = 31 * hash + 字段2贡献分量;

.....

return hash;

参考链接:

https://www.cnblogs.com/lulipro/p/5628750.html

https://blog.csdn.net/haobaworenle/article/details/53819838

https://blog.csdn.net/zhangyuan19880606/article/details/51240372

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值