加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-16 18:08:50 所属栏目:安全 来源:网络整理
导读:我的 Scala版本是2.11.8,Java版本是1.8.0_77. 我有一个自定义类V扩展Ordered [V].我定义了自定义比较和等于.我希望V实例具有,, =, =运算符,并且当它们的某些特定属性相等时可以被认为是相等的. 这是从我的项目中提取的简化代码: class V(val value: Int,val
我的 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,看它们是否相等.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读