hashCode
简介
最近在看dubbo源码时,经常看到System.identityHashCode(obj) 的使用,想了解一下这个跟我们平常的hashcode方法又有啥异同,所以本篇简单的探讨一下。
概念
1、hashCode是 java.lang.Object.hashCode() 或者 java.lang.System.identityHashCode(obj) 会返回的值。他是一个对象的身份标识。官方称呼为:标识哈希码( identity hash code)。
2、哪些特点?
(1)一个对象在其生命期中 identity hash code 必定保持不变;
(2)如果a == b,那么他们的System.identityHashCode() 必须相等;
如果他们的System.identityHashCode() 不相等,那他们必定不是同一个对象(逆否命题与原命题真实性总是相同);
(3)如果System.identityHashCode() 相等的话,并不能保证 a == b(毕竟这只是一个散列值,是允许冲突的)。
3、有什么作用?
加速对象去重:由特征2可知,只要判断出两个对象的hashCode不一致,就知道这两个对象不是同一个;又因为hashCode()的性能比 " == "性能高得多,所以多数时候,用它来判断重复。
扩展:为啥hashCode()性能高?
因为hashCode()的结果算出来后缓存起来,下次调用直接用不需要重新计算,提高性能
identityHashCode
看官方提供的API , 对System.identityHashCode()的解释为 :
public static int identityHashCode([Object] x)
返回给定对象的哈希码,该代码与默认的方法 hashCode() 返回的代码一样,无论给定对象的类是否重写 hashCode()。null 引用的哈希码为 0。
obj.hashcode()
hashCode()方法是顶级类Object类的提供的一个方法,所有的类都可以进行对hashCode方法重写。这时hash值计算根据重写后的hashCode方法计算
异同
从上面的概念可以看出identityHashCode是根据Object类hashCode()方法来计算hash值,无论子类是否重写了hashCode()方法。而obj.hashcode()是根据obj的hashcode()方法计算hash值
验证
@Test
public void testHashCode() {
TestExample example = new TestExample();
int exampleCode = System.identityHashCode(example);
int exampleCode2 = System.identityHashCode(example);
int exampleHashcode = example.hashCode();
System.out.println("example identityHashCode:" + exampleCode);
System.out.println("example2 identityHashCode:" + exampleCode2);
System.out.println("example Hashcode:" + exampleHashcode);
String str = "dd";
String str2 = "dd";
int strCode = System.identityHashCode(str);
int strHashCode = str.hashCode();
int str2HashCode = str.hashCode();
System.out.println("str identityHashCode:" + strCode);
System.out.println("str hashcode:" + strHashCode);
System.out.println("str2 hashcode:" + str2HashCode);
}
输出:
example identityHashCode:1144748369
example2 identityHashCode:1144748369
example Hashcode:1144748369
str identityHashCode:340870931
str hashcode:3200
str2 hashcode:3200
结果分析:
(1)从上面样例可以看出,TestExample 对象没重写HashCode()方法,所以两个都是调用Object的HashCode()方法,自然结果一样。
而String重写了HashCode()方法,identityHashCode和HashCode结果自然不一样。
(2)str和str2的hashCode是相同的,是因为String类重写了hashCode方法,它根据String的值来确定hashCode的值,所以只要值一样,hashCode就会一样。
hashCode如何计算的?
JDK8 hashCode( )源码:
进入openjdk\jdk\src\share\classes\java\lang目录下,可以看到 Object.java源码
public native int hashCode();
即该方法是一个本地方法,Java将调用本地方法库对此方法的实现。由于Object类中有JNI方法调用,按照JNI的规则,应当生成JNI 的头文件,在此目录下执行javah -jni java.lang.Object 指令,将生成一个java_lang_Object.h头文件,

java_lang_Object.h头文件关于hashcode方法的信息如下所示:
/*
* Class: java_lang_Object
* Method: hashCode
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_java_lang_Object_hashCode
(JNIEnv *, jobject);
1. Object对象的hashCode()方法在C语言文件Object.c中实现
打开openjdk\jdk\src\share\native\java\lang目录,查看Object.c文件,可以看到hashCode()的方法被注册成有JVM_IHashCode方法指针来处理:
/*-
* Implementation of class Object
*
* former threadruntime.c, Sun Sep 22 12:09:39 1991
*/
#include <stdio.h>
#include <signal.h>
#include <limits.h>
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
//使用了上面生成的java_lang_Object.h文件
#include "java_lang_Object.h"
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode},//hashcode的方法指针JVM_IHashCode
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
2.JVM_IHashCode方法指针
在 openjdk\hotspot\src\share\vm\prims\jvm.cpp中定义,如下:
// java.lang.Object ///////////////////////////////////////////////
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
如上可以看出,JVM_IHashCode方法中调用了ObjectSynchronizer::FastHashCode方法
3. ObjectSynchronizer::fashHashCode方法的实现:
ObjectSynchronizer::fashHashCode()方法在hotspot\src\share\vm\runtime\synchronizer.cpp
// hashCode() generation :
//
// Possibilities:
// * MD5Digest of {obj,stwRandom}
// * CRC32 of {obj,stwRandom} or any linear-feedback shift register function.
// * A DES- or AES-style SBox[] mechanism
// * One of the Phi-based schemes, such as:
// 2654435761 = 2^32 * Phi (golden ratio)
// HashCodeValue = ((uintptr_t(obj) >> 3) * 2654435761) ^ GVars.stwRandom ;
// * A variation of Marsaglia's shift-xor RNG scheme.
// * (obj ^ stwRandom) is appealing, but can result
// in undesirable regularity in the hashCode values of adjacent objects
// (objects allocated back-to-back, in particular). This could potentially
// result in hashtable collisions and reduced hashtable efficiency.
// There are simple ways to "diffuse" the middle address bits over the
// generated hashCode values:
//
//最终生成hash的方法
static inline intptr_t get_next_hash(Thread * Self, oop obj) {
intptr_t value = 0 ;
if (hashCode == 0) {
// This form uses an unguarded global Park-Miller RNG,
// so it's possible for two threads to race and generate the same RNG.
// On MP system we'll have lots of RW access to a global, so the
// mechanism induces lots of coherency traffic.
value = os::random() ;
} else
if (hashCode == 1) {
// This variation has the property of being stable (idempotent)
// between STW operations. This can be useful in some of the 1-0
// synchronization schemes.
intptr_t addrBits = cast_from_oop<intptr_t>(obj) >> 3 ;
value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
} else
if (hashCode == 2) {
value = 1 ; // for sensitivity testing
} else
if (hashCode == 3) {
value = ++GVars.hcSequence ;
} else
if (hashCode == 4) {
value = cast_from_oop<intptr_t>(obj) ;
} else {
// Marsaglia's xor-shift scheme with thread-specific state
// This is probably the best overall implementation -- we'll
// likely make this the default in future releases.
unsigned t = Self->_hashStateX ;
t ^= (t << 11) ;
Self->_hashStateX = Self->_hashStateY ;
Self->_hashStateY = Self->_hashStateZ ;
Self->_hashStateZ = Self->_hashStateW ;
unsigned v = Self->_hashStateW ;
v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
Self->_hashStateW = v ;
value = v ;
}
value &= markOopDesc::hash_mask;
if (value == 0) value = 0xBAD ;
assert (value != markOopDesc::no_hash, "invariant") ;
TEVENT (hashCode: GENERATE) ;
return value;
}
//ObjectSynchronizer::FastHashCode方法的实现,该方法最终会返回hashcode
intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {
if (UseBiasedLocking) {
// NOTE: many places throughout the JVM do not expect a safepoint
// to be taken here, in particular most operations on perm gen
// objects. However, we only ever bias Java instances and all of
// the call sites of identity_hash that might revoke biases have
// been checked to make sure they can handle a safepoint. The
// added check of the bias pattern is to avoid useless calls to
// thread-local storage.
if (obj->mark