scala可变集合中的HashCode

时间:2015-12-18 12:43:05

标签: scala

在这段代码中

object Program1 extends App {

  val set = scala.collection.mutable.Set( "Abc", "def")
  set += "ghi"

}

因为set在这种情况下是可变的,这意味着它会将元素添加到自身,并且不会创建新的集合,但是当我尝试显示集合的hashCode()时,这样:

object Program1 extends App {

 val set = scala.collection.mutable.Set( "Abc", "def")
 println(set.hashCode)
 set += "ghi"
 println(set.hashCode)

}

我希望println()语句将输出相同的哈希码,但它打印的不同,因为set对象没有更改,我们只是附加到现有的set然后为什么hashcode会有所不同。

2 个答案:

答案 0 :(得分:3)

如果你在scala中查看hashCode可变HashSet的实现,你会发现它散列了所有内部元素。在散列时,我的scala版本会在MurmurHash3.unorderedHash(...)调用时结束。其他人可能会有所不同。

如果你问为什么?我想这是因为Set("Abc", "def") != Set("Abc", "def", "ghi")并且还与不可变HashSet实现一致。这很有道理,我不知道为什么你会这样做。

更新

回答作者评论的其他解释

hashCode是关于平等的,而不是关于同一个对象。规则是如果两个对象相等,那么它们应该返回相同的hashCode。如果他们不是 - 他们最好返回不同(我说更好,因为它仍然可能通过碰撞返回相同)。这适用于所有对象。

考虑以下代码:

import scala.collection.mutable.Set

val s1 = Set(1)
val superSet = Set(s1)
println(superSet.contains(s1)) // prints true
println(superSet.contains(Set(1)) // still prints true

请注意,即使s1Set(1)是内存中的两个不同对象,两者都会打印为true。这是因为他们的equalshashCode返回相同的

现在这个实现存在一个小问题:

import scala.collection.mutable.Set

val superMap = scala.collection.mutable.Map.empty[Set[String], Boolean]

superMap += (set -> true)
println(superMap.contains(set)) // prints true

set += "ghi"
println(superMap.contains(set)) // prints false
println(superMap.contains(Set("Abc", "def"))) // still prints false

第二个println打印false。这是因为Map无法再找到密钥,因为密钥已更改其hashCode,但Map仍会记住旧密钥。第三个println仍未通过检查,因为即使hashCodeMap中的包含Set("Abc", "def").hashCode相同,这些集合也会在之后无法进行等式检查。

这是一个众所周知的问题,没有好的解决方案,所以建议永远不要使用可变对象作为HashMap的键。一般情况下,您不应将可变对象用于hashCode - 检查然后equality - 应用检查的任何结构。同样适用于HashSet

答案 1 :(得分:2)

此功能反映了所有hashCode()equals()实施建议的内容:if a1.equals(a2)然后a1.hashCode() == a2.hashCode()。请查看此处的帖子以获取更多信息https://stackoverflow.com/a/256447/1154145