文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

java Object的hashCode方法怎么使用

2023-06-22 04:35

关注

这篇文章主要讲解了“java Object的hashCode方法怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java Object的hashCode方法怎么使用”吧!

1. 背景介绍

在为重写hashCode方法的时候,看到hashCode打印出的数据像是一个地址值,很是好奇。

加之最近在研读jvm源码,特此一探究竟,看看在hotspot中hashCode究竟是如何实现的。

2. 调用过程梳理

java的Object代码

public native int hashCode();

通过官产jdk的Object.class的源码, 发现hashCode被native修饰. 因此这个方法应该是在jvm中通过c/c++实现

jvm的hashCode相关代码

首先观察Object.java对应的Object.c代码

// 文件路径: jdk\src\share\native\java\lang\Object.cstatic JNINativeMethod methods[] = {    {"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.hJNIEXPORT jint JNICALLJVM_IHashCode(JNIEnv *env, jobject obj); // 此时定了已hashCode方法的接口, 具体实现在jvm.cpp中
// 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)) ; // 如果object为null, 就返回0; 否则就调用ObjectSynchronizer::FastHashCodeJVM_END

进入到ObjectSynchronizer::FastHashCode

// hotspot\src\share\vm\runtime\synchronizer.cppintptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {// .... // 在FastHashCode方法中有一段关键代码: if (mark->is_neutral()) {     hash = mark->hash();              // 首先通过对象的markword中取出hashCode     if (hash) {                       // 如果取调到了, 就直接返回       return hash;     }     hash = get_next_hash(Self, obj);  // 如果markword中没有设置hashCode, 则调用get_next_hash生成hashCode     temp = mark->copy_set_hash(hash); // 生成的hashCode设置到markword中     // use (machine word version) atomic operation to install the hash     test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark);     if (test == mark) {       return hash;     } }// ....}

生成hashCode的方法get_next_hash, 可以支持通过参数配置不同的生成hashCode策略

// hotspot\src\share\vm\runtime\synchronizer.cppstatic inline intptr_t get_next_hash(Thread * Self, oop obj) {  intptr_t value = 0 ;  // 一共支持6中生成hashCode策略, 默认策略值是5  if (hashCode == 0) {  // 策略1: 直接通过随机数生成     value = os::random() ;  } else if (hashCode == 1) {     // 策略2: 通过object地址和随机数运算生成     intptr_t addrBits = cast_from_oop<intptr_t>(obj) >> 3 ;     value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;  } else if (hashCode == 2) {  // 策略3: 永远返回1, 用于测试     value = 1 ;            // for sensitivity testing  } else if (hashCode == 3) {  // 策略4: 返回一个全局递增的序列数     value = ++GVars.hcSequence ;  } else if (hashCode == 4) {  // 策略5: 直接采用object的地址值     value = cast_from_oop<intptr_t>(obj) ;  } else {     // 策略6: 通过在每个线程中的四个变量: _hashStateX, _hashStateY, _hashStateZ, _hashStateW     // 组合运算出hashCode值, 根据计算结果同步修改这个四个值     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; // 通过hashCode的mask获得最终的hashCode值  if (value == 0) value = 0xBAD ;  assert (value != markOopDesc::no_hash, "invariant") ;  TEVENT (hashCode: GENERATE) ;  return value;}

3. 关于hashCode值的大小

前面以及提交到hashCode生成后, 是存储在markword中, 我们在深入看一下这个markword

// hotspot\src\share\vm\oops\markOop.hppclass markOopDesc: public oopDesc { private:  // Conversion  uintptr_t value() const { return (uintptr_t) this; } public:  // Constants  enum { 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. 验证

package test;public class TestHashCode {    public static void main(String[] args) {        Object obj1 = new Object();        Object obj2 = new Object();        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策略值描述
10直接通过随机数生成
21通过object地址和随机数运算生成
32永远返回1, 用于测试
43返回一个全局递增的序列数
54直接采用object的地址值
6其他通过在每个线程中的四个变量: _hashStateX, _hashStateY, _hashStateZ, _hashStateW 组合运算出hashCode值, 根据计算结果后修改这个四个值

默认策略采用策略6, 在globals.hpp文件中定义

  product(intx, hashCode, 5,                                                \          "(Unstable) select hashCode generation algorithm")

感谢各位的阅读,以上就是“java Object的hashCode方法怎么使用”的内容了,经过本文的学习后,相信大家对java Object的hashCode方法怎么使用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯