2013-12-17 70 views
2

Scala in Depthmutabilityequality上呈現此代碼。Scala Equality和HashCode

class Point2(var x: Int, var y: Int) extends Equals { 
def move(mx: Int, my: Int) : Unit = { 
    x = x + mx 
    y = y + my 
} 
override def hashCode(): Int = y + (31*x) 

def canEqual(that: Any): Boolean = that match { 
    case p: Point2 => true 
    case _ => false 
} 
override def equals(that: Any): Boolean = { 
def strictEquals(other: Point2) = 
    this.x == other.x && this.y == other.y 
    that match { 
    case a: AnyRef if this eq a => true 
    case p: Point2 => (p canEqual this) && strictEquals(p) 
    case _ => false 
    } 
} 
} 

然後,它進行評估。

scala> val x = new Point2(1,1) 
x: Point2 = [email protected] 
scala> val y = new Point2(1,2) 
y: Point2 = [email protected] 
scala> val z = new Point2(1,1) 
z: Point2 = [email protected] 

接下來,創建了HashMap

scala> val map = HashMap(x -> "HAI", y -> "WORLD") 
map: scala.collection.immutable.HashMap[Point2,java.lang.String] = 
Map(([email protected],WORLD), ([email protected],HAI)) 

scala> x.move(1,1) 

scala> map(y) 
res9: java.lang.String = WORLD 

我明白map(x)將返回NoSuchElementException因爲x已經變異。由於x.move(1,1的突變,x的hashCode得到重新計算)。因此,當檢查x是否在map中時,沒有任何地圖的hashCodex的新hashCode匹配。

scala> map(x) 
java.util.NoSuchElementException: key not found: [email protected] 
... 

由於z等於(值)最初插入的HashMapx,還有hashCode,爲什麼是拋出的異常?

scala> map(z) 
java.util.NoSuchElementException: key not found: [email protected] 

編輯這個例子,在我看來,顯示命令式編程的複雜(壞)。

+0

確定這是提供的代碼嗎?看起來不正確。 –

+0

我從這裏得到 - http://www.manning.com/suereth/SiD-Sample02.pdf –

回答

5

因爲地圖仍然使用x來測試是否相等。

這裏是發生了什麼:

  • 您在使用x作爲一個關鍵的地圖插入,此時的hashCode是#X。大。
  • 你改變x的一些值,#x現在不見了,新的hashCode是#x。
  • 您嘗試在地圖中查找與x關聯的值。該地圖獲取hashCode:#x'。它不存在於地圖中(因爲在插入時它是#x)。
  • 您創建的zx原來的值相同。
  • 您可以查看與z相關的值。該映射爲z(因爲它是#x)的hashCode找到一個值,但在zx(與第一步中用於插入值的實例相同)上調用equals。因爲你移動了x,所以你得到了false

的地圖保持對關鍵的實例的引用,並用它來測試equals當你get,但它永遠不會重新計算的哈希碼。

+0

Thx。我以前的困惑來自不理解(1)hashCode爲HashMap計算一次,而**從不**變化,(2)該映射保存對'x'的引用,這是對'mutable'的一個'immutable'引用。數據結構。改變'x'字體將要改變的數據結構'map'是相應的'key'對象 –

+0

@KevinMeredith它不是立即顯而易見的,但它是有意義的,因爲2完全不相關(甚至不是相同類型)對象最終可能會得到相同的hashCode,因此地圖需要執行另一次檢查以確保它識別出正確的密鑰。我已經讀過這本書,如果我沒有記錯的話,它不是特別好解釋:) – vptheron