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

我的Scala版本是
2.11.8
,Java版本是
1.8.0\u 77

我有一个定制的类
V
extends
Ordered[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
的源代码,但是我没有发现它是如何处理的,或者我有什么误解吗?@user3295962
Map1
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