看抖音有人问Object#hashcode方法实现,以前面试刷过文章大概记得说是对象的地址,今天从源码一探究竟。
1.jdk源码以及jvm源码下载
jdk源代码相当于jdk接口,而jvm源码相当于jdk接口的实现。我们要找的hashcode方法需要先到jdk源代码找到对应到jvm代码的方法名称,在到jvm源码找到实现。
首先下载两个源代码,网速不好可以用gitee:
| 源码 | github | gitee |
|---|---|---|
| jdk8 | github.com/gorden5566/… | gitee.com/gorden5566/… |
| jvm-hotspot8 | github.com/gorden5566/… | gitee.com/gorden5566/… |
2.从jdk源码中找到hashcode的native定义
下载jdk8代码,用vscode打开,定位到下面目录。
找到Object.c文件,可以看到hashCode方法对应的native方法名称是JVM_IHashCode,下面转到jvm源码找到c方法实现。
3.从jvm源码中找到JVM_IHashCode方法实现
下载完jvm-hotspot后,使用vscode打开,使用用全局搜索功能搜索方法名称JVM_IHashCode,可以直接定位到源码实现:
4.探索hashCode的C代码实现
JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
JVMWrapper("JVM_IHashCode");
// as implemented in the classic virtual machine; return 0 if object is NULL
return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
JVM_END
4.1 jobject是个什么鬼
第一行代码是个判空,所以必须要知道这个参数怎么来的。
我们知道每一个jdk的native方法其实都对应到c语言的一个方法,那么方法的参数也是一一对应么?实际确实如此,但是需要补充this等等参数。
jdouble Java_pkg_Cls_f__ILjava_lang_String_2 (
JNIEnv *env, /* 接口指针 */
jobject obj, /* this 对象指针 */
jint i, /* 参数 1 */
jstring s) /* 参数 2 */
{
/* 复制 java 的 String */
const char *str = (*env)->GetStringUTFChars(env, s, 0);
/* 处理 string */
...
/* 处理完毕 */
(*env)->ReleaseStringUTFChars(env, s, str);
return ...
}
所以对于代码handle == NULL相信你有答案了。
4.2 ObjectSynchronizer::FastHashCode探索
ok,我们探索hashCode源码的目标转为了探索ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle))的源码。
不啰里八嗦打字了,直接上图:
下一步就是探索对象头的hash如何生成,个人猜测两个情况:
- 创建对象头时候一起生成
- 第一次调用hashCode生成
4.3 对象头中hash值生成
我们先按照上面第二个猜测继续看下源码。OMG是我疏忽了,下面一行代码就已经给了答案,验证了第二个猜测是正确的:
4.4 生成hash
进入get_next_hash方法。
结合注释和代码,我发现hotspot生成hash的花样真是多啊,具体用哪个方法生成又是依靠hashCode这个变量判断,依赖vscode,直接跳转定义:
最后来到hashCode类型定义位置,说实话我看不懂最后是不是5,姑且当做5判断。
到这里就完了,怎么算的我从来不去纠结,只要运算结果符合hashCode定义即可:
- 在同一个java程序执行过程中,不论调用hashCode方法多少次,都要返回相同的值,
- 两个对象的equals方法相同,hashCode方法一定相同,
- 两个对象的equals方法不相同,hashCode方法不一定不同,
- 两个对象的hashCode方法不相同,equals方法一定不同,
- 两个对象的hashCode方法相同,equals方法不一定相同。
查了一下资料,可以通过jvm参数指定变量hashCode的值XX:hashCode=4。