以对象引用为键的映射?

Mal*_*lax 3 scala map data-structures

我有一个存储有关特定实例的信息的对象。为此,我想使用 a Map,但因为键不是按引用(它们不是,对吧?),而是作为getHashCode方法提供的散列。为了更好地理解:

import collection.mutable._
import java.util.Random

object Foo {
    var myMap = HashMap[AnyRef, Int]()

    def doSomething(ar: AnyRef): Int = {
        myMap.get(ar) match {
            case Some(x) => x
            case None => {
                myMap += ar -> new Random().nextInt()
                doSomething(ar)
            }
        }
    }
}

object Main {
    def main(args: Array[String]) {
        case class ExampleClass(x: String);
        val o1 = ExampleClass("test1")
        val o2 = ExampleClass("test1")

        println(o2 == o1) // true
        println(o2 eq o1) // false

                    // I want the following two lines to yield different numbers
                    // and i do not have control over the classes, messing with their
                    // equals implementation is not possible.
        println(Foo.doSomething(o1))
        println(Foo.doSomething(o2))
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我有具有相同哈希码的实例,随机值的“缓存”将为两个实例返回相同的值,即使它们不相同。在这种情况下最好使用哪种数据结构?

澄清/编辑

基于hashCodeequals方法,我知道这是如何正常工作的。但这正是我想要避免的。我更新了我的示例以使其更清楚。:)

Mat*_*ell 5

编辑:基于对问题的澄清,您可以创建自己的 Map 实现,并覆盖 elemEquals()。

原始实现(在 HashMap 中)

protected def elemEquals(key1: A, key2: A): Boolean = (key1 == key2)
Run Code Online (Sandbox Code Playgroud)

将此更改为:

protected def elemEquals(key1: A, key2: A): Boolean = (key1 eq key2)

class MyHashMap[A <: AnyRef, B] extends scala.collection.mutable.HashMap[A, B] {
  protected override def elemEquals(key1: A, key2: A): Boolean = (key1 eq key2)
}
Run Code Online (Sandbox Code Playgroud)

请注意,要使用 eq,您需要将键限制为 AnyRef,或者在 elemEquals() 方法中进行匹配。

case class Foo(i: Int)
val f1 = new Foo(1)
val f2 = new Foo(1)
val map = new MyHashMap[Foo, String]()
map += (f1 -> "f1")
map += (f2 -> "f2")
map.get(f1) // Some(f1)
map.get(f2) // Some(f2)
Run Code Online (Sandbox Code Playgroud)

——原答案

Map 与 hashCode() 和 equals() 一起使用。你在你的对象中正确地实现了 equals() 吗?请注意,在 Scala 中,==被转换为对equals(). 要获得与==Java相同的行为,请使用 Scala 运算符eq

case class Foo(i: Int)
val f1 = new Foo(1)
val f2 = new Foo(1)
f1 == f2 // true
f1.equals(f2) // true
f1 eq f2 // false

val map = new MyHashMap (f1 -> "f1", f2 -> "f2")
map.get(f1) // Some("f2")
map.get(f2) // Some("f2")
Run Code Online (Sandbox Code Playgroud)

这里,case 类实现了 equals() 对象等价,在这种情况下:

f1.i == f1.i
Run Code Online (Sandbox Code Playgroud)

您需要覆盖对象中的 equals() 以包含对象相等性,即:

override def equals(o: Any) = { o.asInstanceOf[AnyRef] eq this }
Run Code Online (Sandbox Code Playgroud)

这应该仍然适用于相同的 hashCode()。