Scala:为什么我的案例类实例具有相同的 hashCode?

Ale*_*lex 1 hash scala hashset

我正在使用 Scala 2.11。

我有一个案例类Dimension,并创建了它的 3 个实例。当我将它们放入HashSet时,我惊讶地发现只有 1 被正确添加。然后我尝试调试,发现它们有相同的 hashCode。

我是 Scala 新手,但在 Java 方面有很多经验。我想知道为什么它们都具有相同的 hashCode,即使它们具有不同的字段,以及 Scala 案例类中 hashCode 方法的默认实现是什么?HashSet/HashMap 在 Scala 中如何工作?

这是我的代码示例。

object Echo {
  def main( args:Array[String] ):Unit = {
    var d1 = new Dimension
    d1.name = "d1"
    d1.dimensionId = "1"
    println("d1:" + d1.hashCode()) // d1, d2, d3 have the same hashCode

    var d2 = new Dimension
    d2.name = "d2"
    d2.dimensionId = "2"
    println("d2:" + d2.hashCode())

    var d3 = new Dimension
    d3.name = "d3"
    d3.dimensionId = "3"
    println("d3:" + d3.hashCode())

    var l = List(d1, d2, d3)
    val categories = mutable.HashSet.empty[Dimension]

    l.foreach(md => {
      categories += md
    })

    println(categories.size) // size is 1
  }
}

case class Dimension() {
  var dimensionId: String = _
  var name: String = _
}
Run Code Online (Sandbox Code Playgroud)

And*_*kin 6

引用规范

每个案例类都会隐式覆盖类 scala.AnyRef 的某些方法定义,除非案例类本身已经给出了相同方法的定义,或者在案例类的某个与 AnyRef 不同的基类中给出了相同方法的具体定义。尤其:

  • 方法equals: (Any)Boolean是结构相等,其中如果两个实例都属于所讨论的案例类并且它们具有相等(相对于 equals)构造函数参数(仅限于类的元素,即第一个参数部分),则它们相等。

  • 方法hashCode: Int计算哈希码。如果数据结构成员的 hashCode 方法将相等(相对于 equals)值映射到相等的哈希码,则案例类 hashCode 方法也会这样做。

由于构造函数的参数列表是空的,每个参数列表都是DimensionequalsDimension,因此它们hashCode也必须相同。

只是不要将案例类与那些奇怪的未初始化的混合在一起var,或者至少要更小心地这样做。


SCo*_*uto 5

scala 中的 HashCode 仅考虑案例类构造函数中的属性。

如果您以更实用和更灵活的方式定义案例类(例如确保不变性),则行为将是预期的:

定义

case class Dimension(dimensionId: String, name: String)
val d1 = Dimension("1", "d1")
val d2 = Dimension("2", "d2")
Run Code Online (Sandbox Code Playgroud)

结果

  scala> println("d1:" + d1.hashCode())
    d1:732406741
    scala> println("d2:" + d2.hashCode())
    d2:952021182
Run Code Online (Sandbox Code Playgroud)

您可以在这个很棒的答案中找到 hashcode 方法生成的代码