Hashcode在重播之间不会发生变化

时间:2015-07-19 13:22:28

标签: scala intellij-idea

object Main extends App {
  var a = new AnyRef()
  println(a hashCode)
}

我在Intellij Idea中有这个代码。我注意到重新运行之间的哈希码没有变化。更重要的是,如果我重新开始思考,或者对代码进行一些轻微的修改,它就不会改变。我可以重命名变量a或添加更多变量,但我仍然使用相同的哈希码。

它是否缓存在某个地方?或者只是操作系统为变量分配了相同的地址?这有什么后果吗?

我希望每次都是新的,因为操作系统应该在每次运行时分配新的地址。

4 个答案:

答案 0 :(得分:2)

一些实验:

scala> class A extends AnyRef
defined class A

scala> val a1= new A
a1: A = A@5f6b1f19

scala> val a2 = new A
a2: A = A@d60aa4

scala> a1.hashCode
res19: Int = 1600855833

scala> a2.hashCode
res20: Int = 14027428

scala> val a3 = new AnyRef
a3: Object = java.lang.Object@16c3388e

scala> a3.hashCode
res21: Int = 381892750

因此,显而易见的AnyRef哈希码等于对象的地址。如果我们有相等的哈希值,那么每次重新运行时它的平均对象地址都是相同的。对于我来说,两个人都是如此。 And that is true for me with two repls.

API讲述AnyRef hashCode方法:

  

引用类型的hashCode方法。请参阅scala.Any中的hashCode。

关于任何方法:

  

计算对象的哈希码值。   默认的散列算法取决于平台。

我想该平台确定了对象的位置,因此确定了hashCode的值。

答案 1 :(得分:2)

Object.hashCode()的实现可以在JVM之间有所不同,只要它遵守合同,这不要求运行之间的数字不同。对于HotSpot,甚至有一个选项(-XX:hashCode)来改变实现。

HotSpot的默认设置是使用随机数生成器,因此如果您正在使用它(没有-XX:hashCode选项),那么它似乎在每次运行时使用相同的种子,从而产生相同的哈希码序列。这没什么不对。

lmm的答案是不正确的,除非您使用HotSpot和-XX:hashCode = 4或默认情况下使用此技术的其他JVM。但我完全不确定(你可以尝试使用HotSpot和-XX:hashCode = 4,看看你是否得到另一个在运行之间保持不变的值)。

查看不同选项的代码: http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/tip/src/share/vm/runtime/synchronizer.cpp#l555

在那里有关于使“else”分支成为默认值的注释,即Xorshift模式,它实际上是一个伪随机数生成器,它将始终提供相同的序列。 来自this question的“apangin”的回答说,自JDK8以来,这已成为默认,它解释了您在评论中描述的JDK7的变化。

我可以确认这是正确的,看看JDK8源代码: http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/runtime/globals.hpp#l1127

- >默认值现在为5,对应于“else”分支(Xorshift)。

答案 2 :(得分:0)

任何新进程都会从操作系统获得自己的虚拟地址空间。因此,虽然每次程序运行时进程可能存在于不同的物理地址,但每次都会映射到同一个虚拟地址。 (ASLR存在,但我知道JVM没有参与其中)。你可以用例如一个带有字符串常量的小C程序(你可能不得不故意为该程序禁用ASLR) - 如果你接受一个指向字符串常量的指针并将该指针打印为整数,那么每次它都是相同的值。 p>

答案 3 :(得分:-2)

hashCode()不是随机数。它是分析对象某些部分的消化结果。具有相同值的对象很可能具有相同的哈希码。这适用于您的情况,因为"值"没有字段的AnyRef基本上是空的。