Scala:为什么可变映射和不可变映射在同一自定义类实例上和键有不同的结果?
我的Scala版本是Scala:为什么可变映射和不可变映射在同一自定义类实例上和键有不同的结果?,scala,dictionary,Scala,Dictionary,我的Scala版本是2.11.8,Java版本是1.8.0\u 77 我有一个定制的类VextendsOrdered[V]。我定义了自定义比较和等于。我希望V实例具有,=, 为什么hashCode定义会影响上可变映射的结果 自定义类实例作为键 immutable.Map具有最多4个键值对的自定义实现(Map1,…,Map4)。这些定制实现的get操作没有为hashcode使用内部bucket数组,该数组映射到实际存储值的对象数组,它只是将键值对存储为字段 例如,这里是Map1.get,由getO
2.11.8
,Java版本是1.8.0\u 77
我有一个定制的类V
extendsOrdered[V]
。我定义了自定义比较
和等于
。我希望V
实例具有
,=
,
为什么hashCode
定义会影响上可变映射的结果
自定义类实例作为键
immutable.Map
具有最多4个键值对的自定义实现(Map1
,…,Map4
)。这些定制实现的get
操作没有为hashcode使用内部bucket数组,该数组映射到实际存储值的对象数组,它只是将键值对存储为字段
例如,这里是Map1.get
,由getOrElse
调用:
class Map1[A, +B](key1: A, value1: B) extends AbstractMap[A, B]
with Map[A, B] with Serializable {
def get(key: A): Option[B] =
if (key == key1) Some(value1) else None
相反,mutable.Map
是由mutable.HashMap
支持的,它使用一个bucket来查找对象hashcode,而hashcode又指向对象数组中的值。这些bucket中的对象由它们的hashcode存储。由于您的对象没有实现自定义hashcode方法,因此它从Any
(object
)派生hashcode。因此,可变映射无法在这些存储桶中找到值,因为自定义实现中的相等值没有相等的哈希代码
一旦您实现了自定义hashcode方法,并且它遵守了所有相等的实例都应该生成相同hashcode的规则,HashMap
就能够找到存储对象的正确存储桶,并对这两个对象调用equals
,以查看它们是否相等。答案太棒了!谢谢一些新问题,基于Map1
的get
的实现,我猜是不可变的。Map
使用Map1
(或Map2
,Map3
,Map4
)实例的集合来存储我们的键值?一个Map1
(或Map2
,Map3
,Map4
)实例一个键值?当我们在不可变映射中查找某个键时,immutable.Map
迭代整个内部集合以找到相应的值?对不起,我阅读了immutable.Map
的源代码,但是我没有发现它是如何处理的,或者我有什么误解吗?@user3295962Map1
到Map4
将根据传递给它的apply方法的参数数量来使用(即,当你映射(1->1,2->2)时,你会得到一个Map2
)。关于immutable.Map
,它肯定不会迭代整个集合。Map
的全部含义是,它应该根据值的键提供恒定时间的值查找。
import collection.mutable.ArrayBuffer
val mm = collection.mutable.Map(a -> ArrayBuffer(0, 1), b -> ArrayBuffer(2, 3, 4))
val im = collection.immutable.Map(a -> ArrayBuffer(0, 1), b -> ArrayBuffer(2, 3, 4))
// return scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
mm.getOrElse(new V(1, 0), ArrayBuffer())
// return scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(2, 3, 4)
im.getOrElse(new V(1, 0), ArrayBuffer())
class V(val value: Int, val score: Int = 0) extends Ordered[V] {
def compare(that: V): Int = this.score compare that.score
override def hashCode: Int = value // new method here!
override def equals(that: Any): Boolean = that match {
case that: V => this.value == that.value
case _ => false
}
}
val a = new V(1, 2)
val b = new V(1, 3)
a == b // true
val mm = collection.mutable.Map(a -> ArrayBuffer(0, 1), b -> ArrayBuffer(2, 3, 4))
val im = collection.immutable.Map(a -> ArrayBuffer(0, 1), b -> ArrayBuffer(2, 3, 4))
// both return scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(2, 3, 4)
mm.getOrElse(new V(1, 0), ArrayBuffer())
im.getOrElse(new V(1, 0), ArrayBuffer())
class Map1[A, +B](key1: A, value1: B) extends AbstractMap[A, B]
with Map[A, B] with Serializable {
def get(key: A): Option[B] =
if (key == key1) Some(value1) else None