hashcode值指的是什么_java中常常提起的hashCode到底是个啥?

开始白活

其实这节本来是想聊聊集合的,

但是发现在聊集合之前,

有件事儿是绕不开的,

那就是hashcode编码

Hash我们都知道:

Hash是散列的意思,

就是把任意长度的输入,

通过散列算法变换成固定长度的输出,

该输出就是散列值。

那hashcode呢?

这货到底是个啥?

前情回顾

凑巧我们

正好趁此次我们来回顾一下,

就是在我们没有重写toString()方法时,

直接调用原始的toString()会给我们返回;

【对象的类名称 并 拼接一个16进制】

的hashcode码

(如下图示):

这个内地地址的16机制字符串到底是个什么呢?

我怀着一颗好奇的心,

举着一双欠揍的手,

进行了字符串的转换,

得到的结果

(如下图示):

WHAT ???

特么这货是个啥?

怪我孤陋寡闻…

赶快转换成是10进制压压惊…

(如下图示):

顿时看着舒服多啦…

我们再次进入Object的toString()方法的源码,

(如下图示):

我们发现它是将

@后面hashCode()方法给toHexString()16进制加工了一下;

马上我们会想到,

如果直接调用hashCode()方法,

会得到什么呢?

我们打印一下看结果,

(如下图示):

有同学发现啦,

这不是跟刚才我们在转换工具里得到的值一样吗?

来对照看一下,

(如下图示):

现在是不是脑子好像明白点什么了?

但 仔细一琢磨...

是不是又发现啥也没明白 [捂嘴笑…]

源码浅析

别着急,我们接着往下走,

咱们还是延续上文的套路,

将每种类型的hashcode()函数的源码都调出来,

然后逐一进行分解,

分别是Integer、String、person(Object对象)先来看看Integer

(如下图示):

Integer 包装类,

就是返回值本身,

没什么可多说的。再来看Object类,

(如下图示):

咱们上文说过,

自定义的类都是继承自Object 类,

我们看到Object类使用native关键字,

说到native因为不是本篇的重心,

这里咱们只是简单扩展下,

让同学们知道这是啥咱们目的就达到啦,

当然有兴趣的同学可以自己查查资料,

深入了解一下;

在java源码中使用native关键字,

基本可以判断是调用了非java的代码接口,

例如java需要调用底层接口,

而底层实现的语言可能是使用C++、

或是使用C、或是使用VB等等开发的DLL动态库,

随用随调,避免重复造轮子。

我们都明白既然是非java的代码,

源码肯定是没有权限看到,

我们平时工作一样吗,

自己写了一个组件或者一个服务,

别人要想用,给他们开个口就可以了,

源码肯定不能开放给他们,

道理是一样的。

那么这里的大致意思:

就是Java通过Jvm告知操作系统(咱们现在使用的是Windows)底层

某某函数、某某方法…

我java现在需要用一下;

操作系统接到这个指令;

很通情达理的就给它返回相应结果…最后是String

因为Object咱们看不到源码,

再耗下去也没意思,

快速pass到下环节,

下面是String 类源码,

(如下图示):

这么一看String 类还是最有料的,

那么String的hashCode()函数到底说了个啥呢?

别着急…

我们下运行一下;

先看看结果;

(如下图示):

第一个是Integer类型的根据我们刚刚看到的源码,

符合我们预期,的确是输出了它本身;

第三个Object 调用的是操作系统的hashcode,

返回的十进制数值。通过上文咱们的分析,

看不到源码,也讲不出个所以然。。。

我们现在来着重看看剩到最后的String类型;

有同学可能有疑问;

明明我们给的字符串是的值是“a”;

怎么返回个“97”呢?

同学们可能会想到,

咱们上文刚刚验证过,

已经知道:

hashcode使用的是10进制来表示的;

那“a”的10进制是不是“97”呢?

我们查下ASCII码对照表

(如下图示):

据上图所示;

证明我们的猜测是正确的;

同学们注意啦:

字母大小写是敏感的,

大写和小写的十进制编码是不同的。

“a”的10进制就是用“97”来表示的;

为了更好进一步确认,

我们再换一个字符试一下;

(如下图示):

得出的结果:

[a 为 97 | b 为 98]

手动滚动上文的ASCII码对照表;

对比后;

再次证明是正确的;

完美贴合我们的预设。

卓见成效 ???

是不是发现很简单,

到这里是不是有点小激动,

hhhhhhhh….

稍安勿躁,

我们接着往下看:

这个时候我们将代码稍稍做下调整;

然后再来看一下,

(如下图示):

WHAT THE FU……(文明用语,人人有责,大家不要学博主)

你字符a输出的结果我懂,

你字符b输出的结果我也懂,

a和b这么在一块待着,

输出的这个货——我看不懂。

发生了什么?

输出的值怎么就变成了 “3105”了呢?

按照ASCII码的数值,不应该是“195(97+98)”吗?

那这个“3105”是怎么来的呢?

源码人力跟踪

别着急我们先分析以下源码(注意源码有注释),

如下:

/**

* Returns a hash code for this string. The hash code for a

* {@code String} object is computed as

*

 
  

* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

*

* using {@code int} arithmetic, where {@code s[i]} is the

* ith character of the string, {@code n} is the length of

* the string, and {@code ^} indicates exponentiation.

* (The hash value of the empty string is zero.)

*

* @return a hash code value for this object.

*/

public int hashCode() {

// 起到缓存的效果, 防止反复计算 hashCode

int h = hash;

// 如果 h != 0, 说明已经计算过 hashCode 了, 直接返回缓存值即可

if (h == 0 && value.length > 0) {

char val[] = value;

// 计算的核心步骤是这个 for 循环

for (int i = 0; i < value.length; i++) {

h = 31 * h + val[i];

}

hash = h;

}

return h;

}

根据源码分析我们发现,

函数一进来;

就判断字符串(按照我们的例子就是[s])是否已经hash过(h!=0是否成立)啦,

就被缓存了,直接就返回啦,

如果没有,

就把字符串转换成字符(char[])数组,

进行循环计算;

因为咱们字符串的长度是2,会循环两次,第一次循环后的结果是:

h = 31 * h(默认值是0)+97(字符“a”的10进制表示)

也就是

h = 31 * 0 +97

h = 97 (这符合我们只给字符“a”时返回的结果)第二次循环的结果是:

h = 31 * h(通过第一次循环,此时h已被赋值为“97”) +98(字符“b”的10进制表示)

也就是

h =31 * 97 + 98

h = 3105 (正好是我们页面输出的值)

hashCode的作用

啰里啰嗦说了大半天,

那hashcode的作用是什么?

想要明白hashCode的作用,

那咱们必须要先从Java中的集合说起...

那将又是个不小的话题;

我们决定放在下一篇,

到时仔细说道说道...

要不先给大家看着张截图,

虽然不具有什么代表性,

但也多少能让同学们有点启发;

(如下图示):

看我画的箭头多好看,【一支穿云箭,千军万马来相见...】

hahahahahahahaha.....

再会...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值