2016-08-18 19 views
4

私のScalaバージョンは2.11.8で、Javaバージョンは1.8.0_77です。Scala:なぜマップと不変マップが同じカスタムクラスインスタンス上でキーと異なる結果になるのですか?

私はカスタムクラスを持っていましたVOrdered[V]です。カスタムcompareequalsを定義しました。私は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.Mapmutable.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, 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定義は、カスタムクラスのインスタンス上で変更可能な地図の結果に影響を与えませんキーとして?

答えて

5

キー

immutable.Mapは、4キーと値のペア(Map1、....、Map4)へのカスタム実装を上に持っているとして、なぜhashCode定義は カスタムクラスのインスタンスで変更可能な地図の結果に影響を与えません。これらのカスタマイズされた実装のための操作は、値が実際に格納されているオブジェクト配列にマップするハッシュコードの内部バケット配列を使用せず、単にキーと値のペアをフィールドとして格納します。

例えば、ここに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、によって支えられていますオブジェクト配列内の値。これらのバケット内のオブジェクトは、ハッシュコードによって格納されます。あなたのオブジェクトはカスタムハッシュコードメソッドを実装していないので、ハッシュコードはAnyObject)から派生しています。したがって、変更可能なマップは、ではバケット内の値を見つけることができません。これは、カスタム実装の等しい値が等しいハッシュコードを持たないためです。

カスタムhashCodeメソッドを実装し、それはすべて同じインスタンスが同じハッシュコードを生成する必要があるルールに従う、HashMapがあなたのオブジェクトが格納されている右のバケツを見つけて見て、二つのオブジェクトにequalsを起動することができたら、彼らは平等です。

+0

驚くような答え!ありがとう!いくつかの新しい質問は、 'Map1'の' get'の実装に基づいて '不変です。Map'は 'Map1'(または' Map2'、 'Map3'、' Map4')インスタンスのコレクションを使用してキー値を保存しますか? 1つの 'Map1'(または' Map2'、 'Map3'、' Map4')インスタンスは一つのキー値ですか?不変のMap内でいくつかのキーを検索すると、 'immutable.Map'は内部コレクション全体を反復して対応する値を見つけますか?すみません、私は 'immutable.Map'のソースコードを読んでいますが、どうやって処理するのか見つからなかったのですか、誤解がありますか? – user3295962

+0

@ user3295962 'Map1'から' Map4'への 'Map1'は、あなたが渡す引数の数に応じて使用されます(Map(1 - > 1,2 - > 2)を実行すると、 Map2')。 'immutable.Map'に関して、それは間違いなくコレクション全体を反復しません。 'Map'の全体的な意味は、そのキーに基づいて値を一定の時間で検索することです。 –

関連する問題