首页 > 编程语言 >【有趣的小细节】在Java中native方法hashcode()默认是如何生成哈希码的?

【有趣的小细节】在Java中native方法hashcode()默认是如何生成哈希码的?

时间:2023-10-18 13:03:35浏览次数:69  
标签:Java https Self value hashCode 默认 哈希 HashCodeMode hashcode


之前看其他文章说,hashcode是根据对象的内存地址生成的。但为了满足自己的好奇心,同时验证这个结论是否是真实的,我半个月前深究了一下。今天突然想起来这回事了,把结论记录一下。


结论

目前hashcode的方式有以下六种算法:

  • HashCodeMode==0:由操作系统生成的一个随机数
  • HashCodeMode==1:基于对象内存地址计算哈希值
  • HashCodeMode==2:定值1 ,(始终返回固定的标识哈希码值1,用于测试)。
  • HashCodeMode==3:从零开始递增地计算哈希码值。
  • HashCodeMode==4: 对象的内存地址转为int类型。
  • HashCodeMode>=5:默认算法,它使用Marsaglia的异或移位方案生成的随机数(https://en.wikipedia.org/wiki/Xorshift)。

默认情况下:

  1. JDK8、JDK9下默认是HashCodeMode = 5,即默认并不是通过对象内存地址计算得来的,与对象的内存地址无关
  2. JDK6、JDK7下默认是HashCodeMode = 0

特殊情况:

也可以根据-XX:hashCode=2来调整默认的算法。

证明

JDK6:

【有趣的小细节】在Java中native方法hashcode()默认是如何生成哈希码的?_Self


JDK7

【有趣的小细节】在Java中native方法hashcode()默认是如何生成哈希码的?_对象内存地址_02


JDK8

【有趣的小细节】在Java中native方法hashcode()默认是如何生成哈希码的?_哈希算法_03

JDK9

【有趣的小细节】在Java中native方法hashcode()默认是如何生成哈希码的?_算法_04

代码证明


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

参考

https://hg.openjdk.org/jdk6/jdk6/hotspot/file/5cec449cc409/src/share/vm/runtime/globals.hpp#l1128

https://srvaroa.github.io/jvm/java/openjdk/biased-locking/2017/01/30/hashCode.html
https://hg.openjdk.org/jdk9/jdk9/hotspot/file/fc7e94cb7485/src/share/vm/runtime/globals.hpp#l1198
https://hg.openjdk.org/jdk9/jdk9/hotspot/file/fc7e94cb7485/src/share/vm/runtime/globals.hpp#l1198
https://github.com/openjdk/jdk/blob/master/src/hotspot/share/runtime/globals.hpp


标签:Java,https,Self,value,hashCode,默认,哈希,HashCodeMode,hashcode
From: https://blog.51cto.com/u_13758447/7916378

相关文章

  • Java(Spring) 通过反射classforName获取对象实例导致@Autowired注入失效
    使用策略模式多态获取具体的策略问题描述:classforName在代码中使用反射获取对象实例后,对象实例中通过@Autowrite注解注入的属性值为null(注入失败),导致带反射获取的对象实例调用方法时出现空指针等情况。问题原因:通过反射获取对象实例相当于“new”了一个对象,所以这个对象并没有被......
  • 手写商用Java虚拟机HotSpot,疯狂磨砺技术中
    在当前Java行业激烈竞争的形式下,唯有掌握技术,心中才不能慌。在多年前,我就开始苦练底层技术,但是眼看百遍也不如手过一遍,所以我打算把虚拟机的精华实现部分用手敲出来,这个过程注定不会轻松,但是心态不能着急,要一步一步来,一年二年三年后终能达成。这个过程还会录制一些免费视频,简单介......
  • linux centos7安装配置java环境
    1.先查看本地是否自带java环境:yumlistinstalled|grepjava2.卸载自带的java(输入su,输入root超级管理员的密码,切换到root用户模式)yum-yremovejava-1.8.0-openjdk*yum-yremovetzdata-java*3.查看yum仓库中的java安装包yum-ylistjava*4.安装java:yum-yi......
  • JAVA爬虫被封IP问题的解决方法
    以下是JAVA爬虫被封IP问题的解决方法:解决Java爬虫被封IP问题随着网络技术的发展,Java爬虫在网络应用中越来越普遍,然而在爬取数据的过程中,经常会遇到IP被封的问题。以下是几种常见的解决方法:1.使用代理IP代理IP可以隐藏爬虫的真实IP地址,从而提高爬虫的隐蔽性,减少被封IP的风险。可以......
  • java图片转base64(不换行)
    publicstaticStringImageToBase64(StringimgPath){InputStreamin=null;byte[]data=null;//读取图片字节数组try{in=newFileInputStream(imgPath);data=newbyte[in.available()];in.read(data);in.close();}catc......
  • 【实操】Java+百度ocr,实现图片识别文字小工具
    前言......
  • Java拾贝第四天——动态绑定机制
    Java拾贝不建议作为0基础学习,都是本人想到什么写什么//根据面向对象3中提及的属性看对象,方法看指向。试想如下代码publicclassTest4{publicstaticvoidmain(String[]args){Basebase=newSub();System.out.println(base.sum());System......
  • java学习_01
    字面量类型整数类型不带小数点的数字小数类型带小数点的数字字符串类型用双括号括起来的内容字符类型用单引号括起来的,内容只有一个比如:'a','b','c'布尔类型布尔值,表示真假空类型一个特殊的值,空值null特殊字符'\t'制......
  • Redis的Java客户端
    Jedis以Redis命令作为方法名称,学习成本低,简单实用。但是Jedis实例是线程不安全的,多线程环境下需要基于连接池来使用lettuce(Spring默认使用)Lettuce是基于Netty实现的,支持同步、异步和响应式编程方式,并且是线程安全的。支持Redis的哨兵模式、集群模式和管道模式。RedissionRedisso......
  • java基础漏洞学习----SQL注入漏洞
    java基础漏洞学习----SQL注入漏洞前置基础知识https://www.cnblogs.com/thebeastofwar/p/17759805.html执行SQL语句的几种方式1.Statement执行SQL语句java.sql.Statement是JavaJDBC下执行SQL语句的一种原生方式,执行语句时需要通过拼接来执行若拼接的语句没有经过过滤,将出......