java Object的hashCode方法怎么使用
java Object的hashCode方法怎么使用
这篇文章主要讲解了“javaObject的hashCode方法怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“javaObject的hashCode方法怎么使用”吧!
1. 背景介绍
在为重写hashCode方法的时候,看到hashCode打印出的数据像是一个地址值,很是好奇。
加之最近在研读jvm源码,特此一探究竟,看看在hotspot中hashCode究竟是如何实现的。
2. 调用过程梳理
java的Object代码
publicnativeinthashCode();
通过官产jdk的Object.class的源码, 发现hashCode被native修饰. 因此这个方法应该是在jvm中通过c/c++实现
jvm的hashCode相关代码
首先观察Object.java对应的Object.c代码
//文件路径:jdk\src\share\native\java\lang\Object.cstaticJNINativeMethodmethods[]={{"hashCode","()I",(void*)&JVM_IHashCode},//这个方法就是我们想看的hashCode方法{"wait","(J)V",(void*)&JVM_MonitorWait},{"notify","()V",(void*)&JVM_MonitorNotify},{"notifyAll","()V",(void*)&JVM_MonitorNotifyAll},{"clone","()Ljava/lang/Object;",(void*)&JVM_Clone},};
进一步进入到jvm.h文件中, 这个文件中包含了很多java调用native方法的接口
//hotspot\src\share\vm\prims\jvm.h/**java.lang.Object*/JNIEXPORTjintJNICALLJVM_IHashCode(JNIEnv*env,jobjectobj);//此时定了已hashCode方法的接口,具体实现在jvm.cpp中
//hotspot\src\share\vm\prims\jvm.cpp//java.lang.Object///JVM_ENTRY(jint,JVM_IHashCode(JNIEnv*env,jobjecthandle))JVMWrapper("JVM_IHashCode");//asimplementedintheclassicvirtualmachine;return0ifobjectisNULLreturnhandle==NULL?0:ObjectSynchronizer::FastHashCode(THREAD,JNIHandles::resolve_non_null(handle));//如果object为null,就返回0;否则就调用ObjectSynchronizer::FastHashCodeJVM_END
进入到ObjectSynchronizer::FastHashCode
//hotspot\src\share\vm\runtime\synchronizer.cppintptr_tObjectSynchronizer::FastHashCode(Thread*Self,oopobj){//....//在FastHashCode方法中有一段关键代码:if(mark->is_neutral()){hash=mark->hash();//首先通过对象的markword中取出hashCodeif(hash){//如果取调到了,就直接返回returnhash;}hash=get_next_hash(Self,obj);//如果markword中没有设置hashCode,则调用get_next_hash生成hashCodetemp=mark->copy_set_hash(hash);//生成的hashCode设置到markword中//use(machinewordversion)atomicoperationtoinstallthehashtest=(markOop)Atomic::cmpxchg_ptr(temp,obj->mark_addr(),mark);if(test==mark){returnhash;}}//....}
生成hashCode的方法get_next_hash, 可以支持通过参数配置不同的生成hashCode策略
//hotspot\src\share\vm\runtime\synchronizer.cppstaticinlineintptr_tget_next_hash(Thread*Self,oopobj){intptr_tvalue=0;//一共支持6中生成hashCode策略,默认策略值是5if(hashCode==0){//策略1:直接通过随机数生成value=os::random();}elseif(hashCode==1){//策略2:通过object地址和随机数运算生成intptr_taddrBits=cast_from_oop<intptr_t>(obj)>>3;value=addrBits^(addrBits>>5)^GVars.stwRandom;}elseif(hashCode==2){//策略3:永远返回1,用于测试value=1;//forsensitivitytesting}elseif(hashCode==3){//策略4:返回一个全局递增的序列数value=++GVars.hcSequence;}elseif(hashCode==4){//策略5:直接采用object的地址值value=cast_from_oop<intptr_t>(obj);}else{//策略6:通过在每个线程中的四个变量:_hashStateX,_hashStateY,_hashStateZ,_hashStateW//组合运算出hashCode值,根据计算结果同步修改这个四个值unsignedt=Self->_hashStateX;t^=(t<<11);Self->_hashStateX=Self->_hashStateY;Self->_hashStateY=Self->_hashStateZ;Self->_hashStateZ=Self->_hashStateW;unsignedv=Self->_hashStateW;v=(v^(v>>19))^(t^(t>>8));Self->_hashStateW=v;value=v;}value&=markOopDesc::hash_mask;//通过hashCode的mask获得最终的hashCode值if(value==0)value=0xBAD;assert(value!=markOopDesc::no_hash,"invariant");TEVENT(hashCode:GENERATE);returnvalue;}
3. 关于hashCode值的大小
前面以及提交到hashCode生成后, 是存储在markword中, 我们在深入看一下这个markword
//hotspot\src\share\vm\oops\markOop.hppclassmarkOopDesc:publicoopDesc{private://Conversionuintptr_tvalue()const{return(uintptr_t)this;}public://Constantsenum{age_bits=4,lock_bits=2,biased_lock_bits=1,max_hash_bits=BitsPerWord-age_bits-lock_bits-biased_lock_bits,hash_bits=max_hash_bits>31?31:max_hash_bits,//通过这个定义可知,hashcode可占用31位bit.在32位jvm中,hashCode占用25位cms_bits=LP64_ONLY(1)NOT_LP64(0),epoch_bits=2};}
4. 验证
packagetest;/****可以通过系列参数指定hashCode生成策略*-XX:hashCode=2*/publicclassTestHashCode{publicstaticvoidmain(String[]args){Objectobj1=newObject();Objectobj2=newObject();System.out.println(obj1.hashCode());System.out.println(obj2.hashCode());}}
通过-XX:hashCode=2这种形式, 可以验证上述的5中hashCode生成策略
5. 总结
在64位jvm中, hashCode最大占用31个bit; 32位jvm中, hashCode最大占用25个bit
hashCode一共有六种生成策略
序号 | hashCode策略值 | 描述 |
---|---|---|
1 | 0 | 直接通过随机数生成 |
2 | 1 | 通过object地址和随机数运算生成 |
3 | 2 | 永远返回1, 用于测试 |
4 | 3 | 返回一个全局递增的序列数 |
5 | 4 | 直接采用object的地址值 |
6 | 其他 | 通过在每个线程中的四个变量: _hashStateX, _hashStateY, _hashStateZ, _hashStateW 组合运算出hashCode值, 根据计算结果后修改这个四个值 |
默认策略采用策略6, 在globals.hpp文件中定义
product(intx,hashCode,5,\"(Unstable)selecthashCodegenerationalgorithm")
感谢各位的阅读,以上就是“javaObject的hashCode方法怎么使用”的内容了,经过本文的学习后,相信大家对javaObject的hashCode方法怎么使用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是恰卡编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!