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

时间:2018-07-04 14:41:22

标签: scala hash hashset

我正在使用Scala 2.11。

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

我是Scala的新手,但是在Java方面有很多经验。我想知道为什么即使它们具有不同的字段,它们都具有相同的hashCode?Scala的case类中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 = _
}

3 个答案:

答案 0 :(得分:3)

引用the spec

  

每个案例类都隐式重写该类的某些方法定义   scala.AnyRef,除非已经给出相同方法的定义   在案例类本身或相同方法的具体定义中   在不同于AnyRef的case类的某些基类中给出。   特别是:

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

  •   
  • 方法hashCode: Int计算哈希码。如果   数据结构成员的hashCode方法映射相等(相对于   等于)的值等于相等的哈希码,然后是case类hashCode   方法也可以。

  •   

由于构造函数的参数列表为空,因此每个Dimension都空虚equals和其他Dimension,因此它们的hashCode也必须相同。

请不要将案例类与那些奇怪的未初始化的var混合在一起,或者至少要更仔细地做。

答案 1 :(得分:1)

Scala中的

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

如果您以更实用,更易处理的方式定义案例类(例如,确保不可变性),那么行为将是预期的:

定义

case class Dimension(dimensionId: String, name: String)
val d1 = Dimension("1", "d1")
val d2 = Dimension("2", "d2")

结果

  scala> println("d1:" + d1.hashCode())
    d1:732406741
    scala> println("d2:" + d2.hashCode())
    d2:952021182

您可以在这个很棒的答案here

中找到hashcode方法生成的代码

答案 2 :(得分:1)

如前所述,hashCode使用主要的构造函数args生成其结果。不过,您仍然可以使用vars获得case类的工作版本,例如:

case class Dimension(var dimensionId: String = "", var name: String = "")