Scala:为什么可变Map和不可变Map在同一个自定义类实例上有不同的结果?

时间:2016-08-18 06:26:33

标签: scala dictionary

我的Scala版本为2.11.8,Java版本为1.8.0_77

我有一个自定义类V扩展Ordered[V]。我定义了自定义compareequals。我希望V个实例包含><>=<=个运算符,并且当它们的某些特定属性相等时,可以认为它们相等。

以下是从我的项目中提取的简化代码:

class V(val value: Int, val score: Int = 0) extends Ordered[V] {
  def compare(that: V): Int = this.score compare that.score

  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)

// return true because a.value == b.value
a == b

奇怪的是:

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())

为什么immutable.Mapmutable.Map的结果不同?

但是当我为hashCode定义V时:

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())

为什么hashCode定义会影响自定义类实例上可变Map的结果?

1 个答案:

答案 0 :(得分:5)

  

为什么hashCode定义会影响可变Map的结果   自定义类实例作为键

immutable.Map自定义实施最多4个键值对(Map1,....,Map4)。这些自定义实现的get操作不会将内部存储桶数组用于映射到实际存储值的对象数组的哈希码,它只是将键值对存储为字段。

例如,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.Mapmutable.HashMap支持,它使用存储桶来查找对象哈希码,而哈希码又指向对象数组中的值。这些桶中的对象由其哈希码存储。由于您的对象没有实现自定义哈希码方法,因此它从AnyObject)派生出哈希码。因此,可变映射不能能够在这些存储桶中找到值,因为自定义实现中的相等值不具有相同的哈希码。

实现自定义哈希码方法后,它遵循所有相等实例应生成相同哈希码的规则,HashMap能够找到存储对象的正确存储区并调用equals在这两个对象上,看他们是平等的。