Java中哈希值的计算以及压缩得到索引

本文详细介绍了基本数据类型(如int、float、long、double、boolean、byte、short、char)和字符串的哈希值计算过程,包括整数直接返回值、浮点数转换、长整型的折叠操作等。同时,阐述了字符串哈希值计算中避免碰撞的策略。此外,还讨论了如何将较大哈希值压缩为适合数组索引的值,并指出当哈希值超过数组大小时,通常使用取余操作来确定索引。
摘要由CSDN通过智能技术生成

一.计算哈希值

1.对于基本数据类型四类八种 byte short int long float double char boolean计算过程,大概可分为六类(其实是我自己分的,我只是为了写着清楚)

//第一类 int
       //int类型数据的包装类(因为算hashCode()肯定得是对象嘛,所以包装类)求哈希值,直接返回本身的值

Integer integer = 2147483647;
System.out.println(integer.hashCode());

//第二类 byte short char
       //这三种计算哈希值,直接返回int类型的自身值,跟第一类类似或者说一样

Byte aByte = 127;
System.out.println(aByte.hashCode());

Short aShort = 32767;
System.out.println(aShort.hashCode());

Character character = '0';
System.out.println(character.hashCode());

//第三类 float float也是32位数据,调用Float的floatToIntBits(float f),返回当前值对应二进制的int类型的值

Float aFloat = 32.1321F;
System.out.println(aFloat.hashCode());

//第四类 long long为64位数据,直接转int(32位)的话会有精度损失,因为高32位直接被截断了,所以低32位相同的数值会返回相同的哈希值,
       //这好吗,这不好(请自动脑补马保国老师形象),所以执行一个叫"折叠"的操作

Long aLong = 2147483648L;
//下边这一步就叫做 折叠 folding
//>>>这个叫做无符号右移 32就是右移32位 无符号的意思是右移32位,其余位全都补零
//^这个叫做异或,位不同则为1,相同则为0
int longHashValue = (int) (aLong ^ (aLong >>> 32));//这里的^异或是为了使结果更加"随机"
System.out.println(longHashValue);
System.out.println(aLong.hashCode());

//第五类 double
       //double也是64位数据,有点类似刚才的float和long,只不过把两者合在一起了
       //先调用Double的doubleToLongBits(double d),返回当前值对应二进制的long类型的值
       //然后再对转完的long值进行折叠,整体如下

Double aDouble = 412312.123213;
long tempLong = Double.doubleToLongBits(aDouble);
int doubleHashValue = (int) (tempLong ^ (tempLong >>> 32));
System.out.println(doubleHashValue);
System.out.println(aDouble.hashCode());

//第六类 boolean
       //这没啥说的 一共就俩 true返回1231   false返回1237
       //今天刚看到的时候蒙蔽了,为啥返回这俩数,查了下,为了使哈希值求索引时候尽量平均分配,所以选了这俩大素数
       //不过为啥恰好就是这俩呢,有大神的话给解释一下呗

Boolean aBoolean = true;
System.out.println(aBoolean.hashCode());

2.对字符串求哈希值

上边是对基本数据类型求哈希值,更经常用到的就是对字符串求哈希,下边来说,
对字符串求哈希值,基本的方式就是对字符串内每个字符求一个哈希值,然后加总
但是这样会有个问题,就是字母相同,顺序不同的字符串(如:hello,ohell)会返回相同的哈希值(冲突,碰撞,collision),再一次,这好吗,这不好
所以牛掰的哈希函数考虑了字符串的顺序

String string = "tai";
//f(string) = f(t)*b^2 + f(a)*b^1 + f(i)*b^0 (这个^是次方,从b的(字符串长度-1)次方开始,一直到b的0次方结束),b是一个常数,设计者采用了31(目的就是减少哈希冲突)
int stringHashValue = (31*31*('t'))+(31*('a'))+(1*('i'));//ps.这里的计算实际和java源码的计算顺序是不一样的,这里的字符串只有三位,不会出现结果溢出的情况,
//如果位数多了的话可能会出现(不是可能,一定会出现)溢出,所以下边两个值可能不相等,不过这不影响理解
System.out.println(stringHashValue);
System.out.println(string.hashCode());

二.对哈希值进行"压缩",得到索引

1.由哈希值到索引

上边就是基本类型和字符串类型的计算哈希值的方法,值是计算出来了,后边呢,一般哈希值都是用来求索引的,也就是hashMap hashSet里边用,你懂我意思吧,
但是求出来的哈希值一般都比较大,不太好直接拿来做索引,因为会超出索引范围,假如算出来个哈希值114588,数组一共才16位,怎么做索引,
简单办法就是取余,上边例子,拿114588对16取余,余12,好的,索引就是12了(这个过程叫压缩 compressing)

int hashValue = 114588;
int N = 16;
int index = hashValue % N; //index = 12
//这样可以求出来某个哈希值对应的索引,不过还有快速的方法,这个快是指计算机运行的快,也就是位运算
//当上边的 N 为2的整数次幂时,
index = hashValue & (N -1);//与hashValue % N等价,but faster
// & 代表与运算,都为1,结果才为1

三.结尾:

至此,就基本上明确了基本数据类型和字符串的哈希值计算,及对应索引计算的过程
不过,hashMap和hashSet里边的源码还进行了一些额外的减小哈希碰撞的操作,不过整体就是这么个意思了
对象的哈希还没看,回头看看再写

ps. csdn这排版是真xx难用........

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值