在Scala的case类中的hashCode
我读过Scala'a case class
构造自动生成一个拟合equals
和hashCode
实现。 生成的代码是什么样的?
正如我的教授曾经说过的,只有代码才能说出真相! 所以只要看看为以下代码生成的代码:
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)) })) };