• Java语言中Object对象的hashCode()取值的底层算法是怎样实现的?,object hashcode,图说Java —— 理解Java机制最受欢迎的8幅图


    http://www.bkjia.com/ASPjc/919437.html

     Java语言中,Object对象有个特殊的方法:hashcode(), hashcode()表示的是JVM虚拟机为这个Object对象分配的一个int类型的数值,JVM会使用对象的hashcode值来提高对HashMap、Hashtable哈希表存取对象的使用效率。

          关于Object对象的hashCode()返回值,网上对它就是一个简单的描述:“JVM根据某种策略生成的”,那么这种策略到底是什么呢?我有一个毛病,遇到这种含糊其辞的东西,就想探个究竟,所以,本文就将hashCode()本地方法的实现给扒出来,也给大家在了解hashCode()的过程中提供一点点帮助吧。

          本文将根据openJDK 7源码,向展示Java语言中的Object对象的hashCode() 生成的神秘面纱,我将一步一步地向读者介绍Java Object 的hashcode()方法到底底层调用了什么函数。为了更好地了解这个过程,你可以自己下载openJDK 7 源码,亲自查看和跟踪源码,了解hashCode()的生成过程:

             openJDK 7 下载地址1:http://download.java.net/openjdk/jdk7 (官网,下载速度较慢)

             openJDK 7 下载地址2 :openjdk-7-fcs-src-b147-27_jun_2011.zip (csdn 网友提供的资源,很不错)

            

    1.查看openJDK 关于 java.lang.Object类及其hashcode()方法的定义:

       进入openjdk\jdk\src\share\classes\java\lang 目录下,可以看到 Object.java源码,打开,查看hashCode()的定义如下所示:

    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);
    



    2. Object对象的hashCode()方法在C语言文件Object.c中实现

      打开openjdk\jdk\src\share\native\java\lang\目录,查看Object.c文件,可以看到hashCode()的方法被注册成有JVM_IHashCode方法指针来处理:

    #include <stdio.h>
    #include <signal.h>
    #include <limits.h>
    
    #include "jni.h"
    #include "jni_util.h"
    #include "jvm.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},
    };
    
    JNIEXPORT void JNICALL
    Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
    {
        (*env)->RegisterNatives(env, cls,
                                methods, sizeof(methods)/sizeof(methods[0]));
    }
    
    JNIEXPORT jclass JNICALL
    Java_java_lang_Object_getClass(JNIEnv *env, jobject this)
    {
        if (this == NULL) {
            JNU_ThrowNullPointerException(env, NULL);
            return 0;
        } else {
            return (*env)->GetObjectClass(env, this);
        }
    }

    3.JVM_IHashCode方法指针在 openjdk\hotspot\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

      如上可以看出,JVM_IHashCode方法中调用了ObjectSynchronizer::FastHashCode方法

    4. ObjectSynchronizer::fashHashCode方法的实现:

         ObjectSynchronizer::fashHashCode()方法在openjdk\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:
    //
    
    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 = 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 = 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()->has_bias_pattern()) {
          // Box and unbox the raw reference just in case we cause a STW safepoint.
          Handle hobj (Self, obj) ;
          // Relaxing assertion for bug 6320749.
          assert (Universe::verify_in_progress() ||
                  !SafepointSynchronize::is_at_safepoint(),
                 "biases should not be seen by VM thread here");
          BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current());
          obj = hobj() ;
          assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
        }
      }
    
      // hashCode() is a heap mutator ...
      // Relaxing assertion for bug 6320749.
      assert (Universe::verify_in_progress() ||
              !SafepointSynchronize::is_at_safepoint(), "invariant") ;
      assert (Universe::verify_in_progress() ||
              Self->is_Java_thread() , "invariant") ;
      assert (Universe::verify_in_progress() ||
             ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
    
      ObjectMonitor* monitor = NULL;
      markOop temp, test;
      intptr_t hash;
      markOop mark = ReadStableMark (obj);
    
      // object should remain ineligible for biased locking
      assert (!mark->has_bias_pattern(), "invariant") ;
    
      if (mark->is_neutral()) {
        hash = mark->hash();              // this is a normal header
        if (hash) {                       // if it has hash, just return it
          return hash;
        }
        hash = get_next_hash(Self, obj);  // allocate a new hash code
        temp = mark->copy_set_hash(hash); // merge the hash code into header
        // 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;
        }
        // If atomic operation failed, we must inflate the header
        // into heavy weight monitor. We could add more code here
        // for fast path, but it does not worth the complexity.
      } else if (mark->has_monitor()) {
        monitor = mark->monitor();
        temp = monitor->header();
        assert (temp->is_neutral(), "invariant") ;
        hash = temp->hash();
        if (hash) {
          return hash;
        }
        // Skip to the following code to reduce code size
      } else if (Self->is_lock_owned((address)mark->locker())) {
        temp = mark->displaced_mark_helper(); // this is a lightweight monitor owned
        assert (temp->is_neutral(), "invariant") ;
        hash = temp->hash();              // by current thread, check if the displaced
        if (hash) {                       // header contains hash code
          return hash;
        }
        // WARNING:
        //   The displaced header is strictly immutable.
        // It can NOT be changed in ANY cases. So we have
        // to inflate the header into heavyweight monitor
        // even the current thread owns the lock. The reason
        // is the BasicLock (stack slot) will be asynchronously
        // read by other threads during the inflate() function.
        // Any change to stack may not propagate to other threads
        // correctly.
      }
    
      // Inflate the monitor to set hash code
      monitor = ObjectSynchronizer::inflate(Self, obj);
      // Load displaced header and check it has hash code
      mark = monitor->header();
      assert (mark->is_neutral(), "invariant") ;
      hash = mark->hash();
      if (hash == 0) {
        hash = get_next_hash(Self, obj);
        temp = mark->copy_set_hash(hash); // merge hash code into header
        assert (temp->is_neutral(), "invariant") ;
        test = (markOop) Atomic::cmpxchg_ptr(temp, monitor, mark);
        if (test != mark) {
          // The only update to the header in the monitor (outside GC)
          // is install the hash code. If someone add new usage of
          // displaced header, please update this code
          hash = test->hash();
          assert (test->is_neutral(), "invariant") ;
          assert (hash != 0, "Trivial unexpected object/monitor header usage.");
        }
      }
      // We finally get the hash  ,看到这句话,就特别兴奋,WE FINALLY GET THE HASH!!!!
      return hash;
    }

        

           好了,经过上述如此复杂步骤,终于生成了我们的hashcode了,上述的代码是使用的C++实现的,我是看不懂啦,不过有一点可以确定:

               Java 中Object对象的hashcode()返回值一定不会是Object对象的内存地址这么简单!

           即hashcode()返回的不是对象在内存中的地址。

    Java核心要义_tianjinsong的专栏-CSDN博客

    http://blog.csdn.net/renfufei/article/details/13594715

    原文链接:  Top 8 Diagrams for Understanding Java

    翻译人员: 铁锚

    翻译时间: 2013年10月29日

    世间总是一图胜过千万言!

    下面的8幅图来自于 Program Creek 的 Java教程 ,目前这是该网站最受欢迎的文章.
    希望本文能帮你回顾你已经知道的那些知识。如果图片讲解的不够清晰,你可能需要阅读详细的文章或者进行搜索。

    1. String对象不可改变的特性

    (详情请点击上面的标题查看)

    下图显示了如下代码运行的过程:

    [java]  view plain  copy 
     
      在CODE上查看代码片 派生到我的代码片
     
    1. String s = "abcd";  
    2. s = s.concat("ef");  

    中文参考: Java String 详解 

    图1

    2. equals()与hashCode()方法协作约定

    HashCode(哈希编码,散列码)是设计了用来提高性能的. 
    equals()与hashCode()方法之间的关系可以概括为:
    2.1 如果两个对象相等(equal),那么必须拥有相同的哈希码(hash code)
    2.2 即使两个对象有相同的哈希值(hash code),他们不一定相等.
    中文参考: HashMap的实现原理

    图2



    3. Java 异常类层次结构
    粉红色的是受检查的异常(checked exceptions),其必须被 try{}catch语句块所捕获,或者在方法签名里通过throws子句声明.
    另一类异常是运行时异常(runtime exceptions),需要程序员自己分析代码决定是否捕获和处理。
    而声明为Error的,则属于严重错误,需要根据业务信息进行特殊处理,Error不需要捕捉。
    中文示例:  Exception

    图3



    4. 集合类层次结构关系
    注意Collections(工具类) 和 Collection(集合顶层接口) 的区别:
    中文参考:  Collections

    图4.1

    图4.2





    5. 锁——Java同步的基本思想
    Java同步(synchronization)机制可以用一座大楼来比喻:
    中文参考:  线程同步---synchronized

    图5



    6.Java对象引用处理机制
    别名是指多个引用指向同一个内存地址(对象实际地址,可以理解为这就是对象),甚至这些引用的类型完全不一样.

    图 6



    7. Java 对象在堆中的内存结构
    下图显示了运行时内存中方法和对象所处的地盘
    绝大多数情况下:对象(及其属性域)都保存在堆里面,而方法的参数,局部变量(引用,以及6种基本类型)保存在栈里面.
    当然,极特殊的情况下(极度优化[对象入栈],常量池[String],静态变量[方法区]等)也会打破这个潜规则。

    图 7



    8. JVM 运行时数据区
    下图显示了JVM(Java虚拟机)运行时总体的数据区域划分

    图8



    相关文章:
    1. Java中Set的contains()方法

    2. equals()与hashCode()方法协作约定

    3. Java对象引用处理机制

    4. HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap

    =========================

    工作机会(内部推荐):发送邮件至gaoyabing@126.com,看到会帮转内部HR。

    邮件标题:X姓名X_X公司X_简历(如:张三_东方财富_简历),否则一律垃圾邮件!

    公司信息:

    1. 1.东方财富|上海徐汇、南京|微信客户端查看职位(可自助提交信息,微信打开);
  • 相关阅读:
    pku2226 Muddy Fields
    pku3715 Blue and Red
    关于二分图的最大权匹配
    pku 2262&& pku 2739 && pku 3006
    pku2060 Taxi Cab Scheme
    pku 1486 Sorting Slides
    id、css命名规范
    Git 常用命令
    sublime text3插件使用
    Java实现数据结构栈stack和队列Queue
  • 原文地址:https://www.cnblogs.com/Chary/p/15769464.html
Copyright © 2020-2023  润新知