我的Scala版本为2.11.8
,Java版本为1.8.0_77
。
我有一个自定义类V
扩展Ordered[V]
。我定义了自定义compare
和equals
。我希望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.Map
和mutable.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的结果?
答案 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.Map
由mutable.HashMap
支持,它使用存储桶来查找对象哈希码,而哈希码又指向对象数组中的值。这些桶中的对象由其哈希码存储。由于您的对象没有实现自定义哈希码方法,因此它从Any
(Object
)派生出哈希码。因此,可变映射不能能够在这些存储桶中找到值,因为自定义实现中的相等值不具有相同的哈希码。
实现自定义哈希码方法后,它遵循所有相等实例应生成相同哈希码的规则,HashMap
能够找到存储对象的正确存储区并调用equals
在这两个对象上,看他们是平等的。