在Scala的case类中的hashCode

我读过Scala'a case class构造自动生成一个拟合equalshashCode实现。 生成的代码是什么样的?

正如我的教授曾经说过的,只有代码才能说出真相! 所以只要看看为以下代码生成的代码:

 case class A(i: Int, s: String) 

我们可以指示Scala编译器在不同的阶段之后向我们展示生成的代码,在typechecker之后:

 % scalac -Xprint:typer test.scala [[syntax trees at end of typer]]// Scala source: test.scala package <empty> { @serializable case class A extends java.lang.Object with ScalaObject with Product { .. override def hashCode(): Int = ScalaRunTime.this._hashCode(A.this); ... override def equals(x$1: Any): Boolean = A.this.eq(x$1).||(x$1 match { case (i: Int,s: String)A((i$1 @ _), (s$1 @ _)) if i$1.==(i).&&(s$1.==(s)) => x$1.asInstanceOf[A].canEqual(A.this) case _ => false }); override def canEqual(x$1: Any): Boolean = x$1.$isInstanceOf[A]() }; } 

所以你可以看到哈希码的计算被委托给ScalaRunTime._hashCode ,并且相等取决于case类成员的相等性。

生成的hashCode只是调用scala.runtime.ScalaRunTime._hashCode ,它被定义为:

 def _hashCode(x: Product): Int = { val arr = x.productArity var code = arr var i = 0 while (i < arr) { val elem = x.productElement(i) code = code * 41 + (if (elem == null) 0 else elem.hashCode()) i += 1 } code } 

所以你得到的是elem1 * 41**n + elem2 * 41**(n-1) .. elemn * 1 ,其中n是您的案例类的arity, elemi是案例类的成员。

请注意,在这个问题上以前的答案有点过时的hashCode部分。

从Scala 2.9开始,案例类的hashCode使用MurmurHash : link 。

MurmurHash 产生良好的雪崩效果,良好的分布和CPU友好 。

看起来事情已经改变了, 使用Mirko的例子case class A(i: Int, s: String)我得到:

 override <synthetic> def hashCode(): Int = { <synthetic> var acc: Int = -889275714; acc = scala.runtime.Statics.mix(acc, i); acc = scala.runtime.Statics.mix(acc, scala.runtime.Statics.anyHash(s)); scala.runtime.Statics.finalizeHash(acc, 2) }; 

 override <synthetic> def equals(x$1: Any): Boolean = A.this.eq(x$1.asInstanceOf[Object]).||(x$1 match { case (_: A) => true case _ => false }.&&({ <synthetic> val A$1: A = x$1.asInstanceOf[A]; A.this.i.==(A$1.i).&&(A.this.s.==(A$1.s)).&&(A$1.canEqual(A.this)) })) };