我的天,hash值居然会相等? - 第291篇

我的天,hash值居然会相等? - 第291篇_第1张图片

 

相关历史文章(阅读本文之前,您可能需要先看下之前的系列

色谈Java序列化:女孩子慎入 - 第280篇

烦不烦,别再问我时间复杂度了:这次不色,女孩子进来吧 - 第281篇

双向链表,比西天还远?- 第282篇

面试不再怕,让LRU无处可逃 - 第283篇

爱我,就要懂我 – Memcached- 第284篇

内存管理,难于上青天?- memcached - 第285篇

你懂她,可惜你不懂我「LRU 」- Memcached- 第286篇

分布式算法真是吊炸天 – memcached- Memcached - 第287篇

探索内存碎片化 - 第288篇

Bb你还给老师了吗?- 第289篇

进制8421,这么妖?- 第290篇

 

师傅:徒儿,你看看如下的应该会是怎么结果?

JAVA Code:

String str1 = "Aa";
String str2 = "BB";
System.out.println(str1.equals(str2));
System.out.println(str1.hashCode() == str2.hashCode());

 

上面的打印结果是:

A :true,true

B :true,false

C:false,true  

D:false,false

悟纤:equals肯定是false了,不同的字符串值比较肯定不能相等了。那主要是第二个结果的输出了,我记得之前看到一些资料说hashCode()的结果是【通过对象的内存地址做相关运算得到的】,如果是这这样子的胡啊,那么这两个明显是不同的对象,应该是不会相等吧。据此分析答案应该是D。

师傅:那徒儿你今天有必要认真听一下这一课了。

 

一、常见类型的hashCode

师傅:来,徒儿,为师先给你看一个漂亮的美女,不,是展示一段酷炫的代码。

我的天,hash值居然会相等? - 第291篇_第2张图片

JAVA Code:

 

Integer a = 10;
System.out.println(a.hashCode());//10
String str = "A";
System.out.println(str.hashCode());//65
Date date = new Date();
System.out.println(date.hashCode());//-976369987
String ss = new String("123");
System.out.println(ss.hashCode());//48690
MeiMei meimei = new MeiMei();
System.out.println(meimei.hashCode());//2018699554

 

打印输出结果:

10

65

-975968356

48690

2018699554

预想:

1)、Integer类型的数据,返回的hash值为数据本身;

2)、对象类型的数据,返回的一串字符;

3)、String类型的数据,返回一串字符;

       要看我们的预想的正确性需要了解下hashCode是何女人,让美女带你装逼带飞升^_^。

 

我的天,hash值居然会相等? - 第291篇_第3张图片

二、Object.hashCode()竟这么拽?

师傅:来打开你的java.lang.Object。

八戒:怎么打开呢?

悟纤:不怕虎一样的敌人,就怕猪一样的队友。

悟纤:随便一个开发工具都能查看源码。

悟纤:哇卡哇卡,啥都没有呢??

public native int hashCode();

师傅:不要大惊小怪,native就是本地方法调用,搞得没见过女人一样。

我的天,hash值居然会相等? - 第291篇_第4张图片

悟纤:师傅,徒儿一直和你在一起,哪有时间约美眉呐。

 

    在Java中native标记的方法就是本地方法调用,使用JNI技术调用本地C++代码编写的方法。

       这里就不展开分析c++中的hashCode,感兴趣的可以看一下这一篇文章:

https://www.jianshu.com/p/be943b4958f4。

       这里看一下文章的结论:

OpenJDK8 默认hashCode的计算方法是通过和当前线程有关的一个随机数+三个确定值,运用Marsaglia's xorshift scheme随机数算法得到的一个随机数。和对象内存地址无关。

 

三、Integer.hashCode()返回的hash为数据本身?

       Integer.hashCode是否是返回的本身,这个就可以使用源码进行查看了,Integer这个类重写了hashCode方法:

 

public static int hashCode(int value) {
        return value;
}

       可以看到就是返回了value值本身。

 

四、String.hashCode()又是什么?

       查看String.hashCode源码:

 

   public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

 

       这段代码如何理解:

(1)int h = hash:hash是全局变量,默认值为0,这个主要是为了不用重复计算,二次调用就直接返回h的值了。

(2)if(h==0 && value.length>0) : h不为0,并且string的值的长度大于0的,执行hash值的计算。所以这里得出String s =""的hashCode的值应该为0。

(3) for循环:在for循环中就是遍历字符串中的字符。这里的val[i]是字符串对应的ASCII。(A= 65,a = 97)。

       For循环的公式就是:

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

       这里为什么选择31这个数呐?

首先质数31作为参数进行计算,哈希值不容易冲突,分布比较均匀,且没有超出int范围。再次,31可以被jvm优化,i*31=(1<<5)-i,即进行左移位运算,快很多。

       我们来手动计算一下"AB"的hashCode是多少?

计算过程为:

(1)、(31*0+'A') = 65

(2)、(31*0+'A')*31+'B' = 65*31+66 = 2081

       通过代码测试得到的结果也是2081。

       到这里,我们一开始提出的问题"Aa"和"BB"的hashcode是否相等,那么就是他们这个计算结果是否相等了。

hashCode(Aa) = (31*0+'A')*31+'a'= 65*31+97 = 2112。

 

hashCode(BB) = (31*0+'B')*31+'B'

= 66*31 + 66 

= (65+1)*31+66 

= 65*31+31+66=65*31+97 = 2112。

       好了,本篇介绍就到此为止了,至于date为什么是负数的值呐,源码自己去看看,就知其所以然了。

悟纤:师傅,你这一波操作,好骚呀,让我都不能懂装不懂了。

师傅:徒儿,你还得好好修炼修炼。

悟纤:徒儿,遵命,这就去修炼修炼。

我的天,hash值居然会相等? - 第291篇_第5张图片

 

我就是我,是颜色不一样的烟火。
我就是我,是与众不同的小苹果。

学院中有Spring Boot相关的课程:

à悟空学院:https://t.cn/Rg3fKJD

SpringBoot视频:http://t.cn/A6ZagYTi

Spring Cloud视频:http://t.cn/A6ZagxSR

SpringBoot Shiro视频:http://t.cn/A6Zag7IV

SpringBoot交流平台:https://t.cn/R3QDhU0

SpringData和JPA视频:http://t.cn/A6Zad1OH

SpringSecurity5.0视频:http://t.cn/A6ZadMBe

Sharding-JDBC分库分表实战:http://t.cn/A6ZarrqS

分布式事务解决方案「手写代码」:http://t.cn/A6ZaBnIr

 

你可能感兴趣的:(我的天,hash值居然会相等? - 第291篇)