【问题标题】:Map of with object references as keys?以对象引用为键的映射?
【发布时间】:2011-11-10 13:59:33
【问题描述】:

我有一个存储特定实例信息的对象。为此,我想使用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))
    }
}

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

澄清/修改

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

【问题讨论】:

    标签: scala data-structures map


    【解决方案1】:

    编辑:根据对问题的说明,您可以创建自己的 Map 实现,并覆盖 elemEquals()。

    原始实现(在HashMap中)

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

    将其更改为:

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

    注意,要使用 eq,你需要将 key 限制为 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)
    

    -- 原答案

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

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

    f1.i == f1.i
    

    您需要在对象中覆盖 equals() 以包含对象相等性,例如:

    override def equals(o: Any) = { o.asInstanceOf[AnyRef] eq this }
    

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

    【讨论】:

    • 查看我对 huynhjl 回答的评论。 :)
    • @Malax 不明白,我是说你需要在你的类中覆盖 equals 并使用 eq,而不是 equals()/==
    【解决方案2】:

    您也可以将IdentityHashMapscala.collection.JavaConversions 一起使用。

    【讨论】:

      【解决方案3】:

      啊,基于评论...您可以使用覆盖等于具有引用语义的包装器。

      class EqWrap[T <: AnyRef](val value: T) {
        override def hashCode() = if (value == null) 0 else value.hashCode
        override def equals(a: Any) = a match {
          case ref: EqWrap[_] => ref.value eq value
          case _ => false
        }
      }
      object EqWrap {
        def apply[T <: AnyRef](t: T) = new EqWrap(t)
      }
      
      case class A(i: Int)
      
      val x = A(0)
      val y = A(0)
      
      val map = Map[EqWrap[A], Int](EqWrap(x) -> 1)
      val xx = map.get(EqWrap(x))
      val yy = map.get(EqWrap(y))
      //xx: Option[Int] = Some(1)
      //yy: Option[Int] = None
      

      原始答案(基于不理解问题 - 我必须留下这个,以便评论有意义......)

      地图已经有这个语义(除非我不明白你的问题)。

      scala> val x = A(0)
      x: A = A(0)
      
      scala> val y = A(0)
      y: A = A(0)
      
      scala> x == y
      res0: Boolean = true // objects are equal
      
      scala> x.hashCode
      res1: Int = -2081655426
      
      scala> y.hashCode
      res2: Int = -2081655426 // same hash code
      
      scala> x eq y
      res3: Boolean = false // not the same object
      
      scala> val map = Map(x -> 1)
      map: scala.collection.immutable.Map[A,Int] = Map(A(0) -> 1)
      
      scala> map(y)
      res8: Int = 1 // return the mapping based on hash code and equal semantic
      

      【讨论】:

      • 是的,这就是我想要避免的。我想要它基本上相反。在您的示例中,map(y) 不应返回任何内容,因为y 本身不在Map 内。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-08
      • 1970-01-01
      • 1970-01-01
      • 2020-04-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多