龙空技术网

hashcode详解,快来看看你掌握多少了

合一学社 711

前言:

此时兄弟们对“netgethashcode”大约比较关怀,咱们都需要分析一些“netgethashcode”的相关资讯。那么小编在网络上搜集了一些关于“netgethashcode””的相关资讯,希望看官们能喜欢,你们快快来了解一下吧!

1、什么是hashcode:

想要了解什么是hashcode,我们需要先知道hash和hash表是什么。

hash:

Hash,一般翻译做“散列”,也有直接音译为“哈希”,就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

常用HASH函数:

·直接取余法:f(x):= x mod maxM ; maxM一般是不太接近 2^t 的一个质数。

·乘法取整法:f(x):=trunc((x/maxX)*maxlongit) mod maxM,主要用于实数。

·平方取中法:f(x):=(x*x div 1000 ) mod 1000000); 平方后取中间的,每位包含信息比较多。

hash表:

hash表也称散列表(Hash table),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。简单理解就是:在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。

有了前面的详细解释,我们现在就来说说什么是hashcode:

hashcode:

hashcode就是通过hash函数得来的,通俗的说,就是通过某一种算法得到的,hashcode就是在hash表中有对应的位置。

每个对象都有hashcode,对象的hashcode怎么得来的呢?

首先一个对象肯定有物理地址,在别的文章中会hashcode说成是代表对象的地址,这里肯定会让读者形成误区,对象的物理地址跟这个hashcode地址不一样,hashcode代表对象的地址说的是对象在hash表中的位置,物理地址说的对象存放在内存中的地址,那么对象如何得到hashcode呢?通过对象的内部地址(也就是物理地址)转换成一个整数,然后该整数通过hash函数的算法就得到了hashcode,所以,hashcode是什么呢?就是在hash表中对应的位置。这里如果还不是很清楚的话,举个例子,hash表中有 hashcode为1、hashcode为2、(...)3、4、5、6、7、8这样八个位置,有一个对象A,A的物理地址转换为一个整数17(这是假如),就通过直接取余算法,17%8=1,那么A的hashcode就为1,且A就在hash表中1的位置。

2、hashcode的作用:

可能大家会有这样的疑问,为什么hashcode不直接写物理地址呢,还要另外用一张hash表来代表对象的地址?接下来就告诉你hashcode的作用。

HashCode的存在主要是为了查找的快捷性,HashCode是用来在散列存储结构中确定对象的存储地址的(后半句说的用hashcode来代表对象就是在hash表中的位置)

为什么hashcode就查找的更快

举例:我们有一个能存放1000个数这样大的内存中,在其中要存放1000个不一样的数字,用最笨的方法,就是存一个数字,就遍历一遍,看有没有相同得数,当存了900个数字,开始存901个数字的时候,就需要跟900个数字进行对比,这样就很麻烦,很是消耗时间,用hashcode来记录对象的位置,来看一下。hash表中有1、2、3、4、5、6、7、8个位置,存第一个数,hashcode为1,该数就放在hash表中1的位置,存到100个数字,hash表中8个位置会有很多数字了,1中可能有20个数字,存101个数字时,他先查hashcode值对应的位置,假设为1,那么就有20个数字和他的hashcode相同,他只需要跟这20个数字相比较(equals),如果每一个相同,那么就放在1这个位置,这样比较的次数就少了很多,实际上hash表中有很多位置,这里只是举例只有8个,所以比较的次数会让你觉得也挺多的,实际上,如果hash表很大,那么比较的次数就很少很少了。 通过对原始方法和使用hashcode方法进行对比,我们就知道了hashcode的作用,并且为什么要使用hashcode了。

3、 hashCode()和equals():

Java的基类Object中的 equals()方法用于判断两个对象是否相等,hashCode()方法用于计算对象的哈希码。equals()和hashCode()都不是final方法,都可以被重写(overwrite)

equals方法:

Object类中equals()方法实现如下

根据该实现可以得知,Object类的实现采用了区分度最高的算法,即只要两个对象不是同一个对象,那么equals()一定返回false。虽然可以重写equals()方法,但是有一些注意事项;JDK中说明了实现equals()方法应该遵守的约定自反性:x.equals(x)必须返回true。对称性:x.equals(y)与y.equals(x)的返回值必须相等。传递性:x.equals(y)为true,y.equals(z)也为true,那么x.equals(z)必须为true。一致性:如果对象x和y在equals()中使用的信息都没有改变,那么x.equals(y)值始终不变。非null:x不是null,y为null,则x.equals(y)必须为false。

hashCode 方法:

Object类中hashCode()方法的声明如下:

可以得知,hashCode()是一个native方法,而且返回值类型是整形;实际上,该native方法将对象在内存中的地址作为哈希码返回,可以保证不同对象的返回值不同。

与equals()方法类似,hashCode()方法可以被重写。JDK中对hashCode()方法的作用,以及实现时的注意事项做了说明:

(1)hashCode()在哈希表中起作用,如java.util.HashMap。

(2)如果对象在equals()中使用的信息都没有改变,那么hashCode()值始终不变。

(3)如果两个对象使用equals()方法判断为相等,则hashCode()方法也应该相等。

(4)如果两个对象使用equals()方法判断为不相等,则不要求hashCode()也必须不相等;但是开发人员应该认识到,不相等的对象产生不相同的hashCode可以提高哈希表的性能。

4、重写hashcode()的原则

(1)如果重写了equals()方法,检查条件“两个对象使用equals()方法判断为相等,则hashCode()方法也应该相等”是否成立,如果不成立,则重写hashCode ()方法。

(2)hashCode()方法不能太过简单,否则哈希冲突过多。

(3)hashCode()方法不能太过复杂,否则计算复杂度过高,影响性能

5、hashCode()重写方法

《Effective Java》中提出了一种简单通用的hashCode算法:

初始化一个整形变量,为此变量赋予一个非零的常数值,比如int result = 17;

选取equals方法中用于比较的所有域(之所以只选择equals()中使用的域,是为了保证上述原则的第1条),然后针对每个域的属性进行计算:

(1) 如果是boolean值,则计算f ? 1:0

(2) 如果是bytecharshortint,则计算(int)f

(3) 如果是long值,则计算(int)(f ^ (f >>> 32))

(4) 如果是float值,则计算Float.floatToIntBits(f)

(5) 如果是double值,则计算Double.doubleToLongBits(f),然后返回的结果是long,再用规则(3)去处理long,得到int

(6) 如果是对象应用,如果equals方法中采取递归调用的比较方式,那么hashCode中同样采取递归调用hashCode的方式。否则需要为这个域计算一个范式,比如当这个域的值为null的时候,那么hashCode 值为0

(7) 如果是数组,那么需要为每个元素当做单独的域来处理。java.util.Arrays.hashCode方法包含了8种基本类型数组和引用数组的hashCode计算,算法同上。

C、最后,把每个域的散列码合并到对象的哈希码中。

接下来我们举例子说明。在这个例子中,Person类重写了equals()方法和hashCode()方法。因为equals()方法中只使用了name域和age域,所以hashCode()方法中,也只计算name域和age域。

对于String类型的name域,直接使用了String的hashCode()方法;对于int类型的age域,直接用其值作为该域的hash。

对编程感兴趣,想了解更多的编程知识,关注头条号一起玩转编程

更多编程资讯、干货持续更新中~

标签: #netgethashcode