object Main extends App {
var a = new AnyRef()
println(a hashCode)
}
我在Intellij Idea中有这个代码。我注意到重新运行之间的哈希码没有变化。更重要的是,如果我重新开始思考,或者对代码进行一些轻微的修改,它就不会改变。我可以重命名变量a
或添加更多变量,但我仍然使用相同的哈希码。
它是否缓存在某个地方?或者只是操作系统为变量分配了相同的地址?这有什么后果吗?
我希望每次都是新的,因为操作系统应该在每次运行时分配新的地址。
答案 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哈希码等于对象的地址。如果我们有相等的哈希值,那么每次重新运行时它的平均对象地址都是相同的。对于我来说,两个人都是如此。
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
基本上是空的。