• java中Object的默认hashCode方法实现原理


    前言

    java中哈希码有以下约定:

    在同一个java程序执行过程中,不论调用hashCode方法多少次,都要返回相同的值,
    两个对象的equals方法相同,hashCode方法一定相同,
    两个对象的equals方法不相同,hashCode方法不一定不同,
    两个对象的hashCode方法不相同,equals方法一定不同,
    两个对象的hashCode方法相同,equals方法不一定相同。
    

    hashCode()在Object中是一个native方法,注释上说是对象的内存地址转换的一个值,那么到底是不是呢,我们以openjdk8源码为例来探究一下。

    源码分析

    具体的源码追踪过程可以看 How does the default hashCode() work?源码入口

    // src/share/vm/prims/jvm.cpp
    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
    // 这里是作者简化过的伪码
    // src/share/vm/runtime/synchronizer.cpp
    intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {
        mark = monitor->header();
        ...
        hash = mark->hash();
        if (hash == 0) {
        hash = get_next_hash(Self, obj);
        ...
        }
        ...
        return hash;
    }
    static inline intptr_t get_next_hash(Thread * Self, oop obj) {
      intptr_t value = 0 ;
      if (hashCode == 0) {
         value = os::random() ;
      } else
      if (hashCode == 1) {
         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 ;
      }
    ...
      return value;
    }
    product(intx, hashCode, 5,
        "(Unstable) select hashCode generation algorithm") 
    // src/share/vm/runtime/thread.cpp
      _hashStateX = os::random() ;
      _hashStateY = 842502087 ;
      _hashStateZ = 0x8767 ;    // (int)(3579807591LL & 0xffff) ;
      _hashStateW = 273326509 ;
    

    get_next_hash()方法一共提供了六种实现

    0. 随机数
    1. 内存地址做移位再和一个随机数做异或
    2. 固定值1
    3. 自增序列的当前值
    4. 内存地址
    5. 当前线程有关的一个随机数+三个确定值,运用xorshift随机数算法得到的一个随机数
    

    默认使用的5,第六种实现,和内存地址是无关的,我们也可以通过在JVM启动参数中添加-XX:hashCode=4,改变默认的hashCode计算方式。
    一个对象创建了哈希码之后会将值保存到对象的对象头中,避免下次创建,在垃圾回收过程中,哈希码也不会改变。

    参考

    开发中常见的一些Hash函数(一)
    How does the default hashCode() work?
    Java Object.hashCode()返回的是对象内存地址?

  • 相关阅读:
    布局页js文件问题
    sqlite如何更改表结构
    css各种样式
    layUI订单实现思路
    layUI使用总结
    easyui点击行内编辑,怎么获取行数据并赋值
    404
    PTA C语言作业
    python一行代码格式化日期
    校园网跨网段共享文件Samba+SSH
  • 原文地址:https://www.cnblogs.com/strongmore/p/14501560.html
Copyright © 2020-2023  润新知