我发现了一个我可以理解的可变集的奇怪行为:
我有一个对象,我想添加到一个集合 . 该类的equals方法被覆盖 . 当我向set添加两个不同的对象时,它为equals方法产生相同的输出,我在contains方法的可变和不可变集之间得到了不同的行为 .
这是代码片段:
class Test(text:String){
override def equals(obj:Any) = obj match {
case t: Test => if (t.text == this.text) true else false
case _ => false
}
override def toString = text
}
val mutableSet:scala.collection.mutable.Set[Test] = scala.collection.mutable.Set.empty
mutableSet += new Test("test")
println(mutableSet)
println(mutableSet.contains(new Test("test")))
val immutableSet:scala.collection.immutable.Set[Test] = scala.collection.immutable.Set.empty
immutableSet += new Test("test")
println(immutableSet)
println(immutableSet.contains(new Test("test")))
这产生了输出:
Set(test)
false
Set(test)
true
在我看来,contains的两个调用应该产生相同的输出(true) .
任何人都可以帮助我理解这里的区别,或者这是scala不可变集实现中的错误吗?顺便说一句,我使用scala 2.8.1.final
谢谢 .
2 回答
实现equals()时的规则1:同时实现hashCode() . 见Overriding equals and hashCode in Java
在第一个示例中,您将创建一个可变集,该集调用hashCode来设置哈希表 .
在第二个中,您使用的是一个带有一个条目的不可变集,因此Scala实际上使用了一个名为 Set1 的Set的优化版本 . Set1.contains()只是直接使用equals()将一个条目与传递的元素进行比较 . 这看起来像:
没有调用hashCode . 还有Set2,Set3和Set4 .
因此,如果我们将您的代码更改为:
在equals中添加hashCode和println,输出为:
这解释了为什么mutable.contains()无法正常工作 . 它正在查找错误的哈希表条目中的对象,甚至没有调用equals() . 并且,毫不奇怪,它没有找到它 .
您可以使用text.hashCode实现hashCode:
您还需要覆盖
hashCode
. 覆盖equals
时,hashCode
是必不可少的 .注意还有一些没有编译的东西,所以我编辑了一下:
我建议阅读http://www.artima.com/pins1ed/object-equality.html以获得有关对象平等的更多见解 . 这是开眼界 .