我正在使用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 = _
}
答案 0 :(得分:3)
引用the spec:
每个案例类都隐式重写该类的某些方法定义 scala.AnyRef,除非已经给出相同方法的定义 在案例类本身或相同方法的具体定义中 在不同于AnyRef的case类的某些基类中给出。 特别是:
方法
equals: (Any)Boolean
是结构相等,其中两个 如果实例均属于相关案例类,则实例相等 并且它们具有相等(相对于相等)的构造函数参数 (仅限于类的元素,即第一个参数 部分)。方法
hashCode: Int
计算哈希码。如果 数据结构成员的hashCode方法映射相等(相对于 等于)的值等于相等的哈希码,然后是case类hashCode 方法也可以。
由于构造函数的参数列表为空,因此每个Dimension
都空虚equals
和其他Dimension
,因此它们的hashCode
也必须相同。
请不要将案例类与那些奇怪的未初始化的var
混合在一起,或者至少要更仔细地做。
答案 1 :(得分:1)
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 = "")