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

前端之家收集整理的这篇文章主要介绍了Scala:为什么可变Map和不可变Map在同一个自定义类实例上有不同的结果?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我的 Scala版本是2.11.8,Java版本是1.8.0_77.

我有一个自定义类V扩展Ordered [V].我定义了自定义比较和等于.我希望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,4))

// return scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
mm.getOrElse(new V(1,0),ArrayBuffer())

// return scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(2,4)
im.getOrElse(new V(1,ArrayBuffer())

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

但是当我为V定义hashCode时:

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,3)

a == b // true

而这一次,结果是一样的:

val mm = collection.mutable.Map(a -> ArrayBuffer(0,4))

// both return scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(2,4)
mm.getOrElse(new V(1,ArrayBuffer())
im.getOrElse(new V(1,ArrayBuffer())

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

解决方法

Why does hashCode definition affect the result of mutable Map on
custom class instance as key

immutable.Map具有最多4个键值对的自定义实现(Map1,….,Map4).这些自定义实现的get操作不使用内部存储桶数组来映射到实际存储值的对象数组,它只是将键值对存储为字段.

例如,这是由getOrElse调用的Map1.get:

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的后盾,它使用一个桶来查找对象hashcode,而hashcode又指向对象数组中的值.这些桶中的对象由其哈希码存储.由于您的对象没有实现自定义哈希码方法,因此它从Any(Object)派生它的哈希码.因此,可变映射无法在这些存储桶中找到值,因为自定义实现中的相等值不具有相等的哈希码.

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

猜你在找的Scala相关文章