程式扎記: [Scala 小學堂] Scala Gossic : 了解更多 - 使用繼承 (物件相等性)

標籤

2016年6月30日 星期四

[Scala 小學堂] Scala Gossic : 了解更多 - 使用繼承 (物件相等性)

轉載自 這裡 
前言 : 
Scala 是一個可直譯、編譯、靜態、運行於 JVM 之上、可與 Java 互操作、融合物件導向編程特性與函式編程風格的程式語言. Scala 的繼承作了一些限制,這使你在使用繼承前必須多一份思考. 

物件相等性 : 
在 Scala 中,如果要比較兩個物件的實質相等性,可以使用 == 或 !=,例如 : 
  1. val s1 = new String("Java")  
  2. val s2 = new String("Java")  
  3. println(s1 == s2)       // 顯示 true  
  4. println(s1 eq s2)       // 顯示 false  
雖然兩個物件是新建構出來的,s1 與 s2 是參考到不同物件,但在 Scala 中使用 == 是比較兩個字串的實質字元序列,所以結果會是 true,在 Scala 中若要測試兩個參考是否為同一物件,則可以使用 eq 或 ne 方法== 與 != 方法有兩個版本,一個版本是定義在scala.Any 中,Any 是 Scala 中所有類別的最頂層父類別,其中 == 與 != 的方法定義為 : 
final def ==(arg0 : Any) : Boolean
final def !=(arg0 : Any) : Boolean

在 API 文件說明中表示,== 的作用等於 equals() 的作用 : 
def equals(arg0 : Any) : Boolean

equals() 的作用是測試兩個 args0 的作用與 this 是否參考同一物件. 而 != 等於 == 的反相結果,也就是 o != arg0 等於 !(o == (arg0)). 事實上,當你在 Scala 中定義一個類別時沒有明確指定父類別,則會繼承 scala.AnyRef相當於 Java 的 java.lang.Object),這是 Any 的直接子類別。AnyRef 定義了== 與 !=,其版本為 : 
final def ==(arg0 : AnyRef) : Boolean
final def !=(arg0 : AnyRef) : Boolean

!=等於==的反相結果,而==的定義內容相當於 : 
  1. final def == (arg0 : Any): Boolean =   
  2.     if (this eq null) arg0 eq null else this.equals(arg0)  
eq 與 ne 方法,是定義在 AnyRef 中(在 Scala 中,像 1 這樣的物件是 scala.AnyVal 的實例,[color=red]AnyVal 是 Any 的直接子類別,所以 scala.AnyVal 沒有 eq  ne 方法,scala.AnyVal 物件只要值相同,一定是同一個物件實例,也就是 1 equals 1結果一定是 true): 
final def eq(arg0 : AnyRef) : Boolean
final def ne(arg0 : AnyRef) : Boolean

ne 為 eq 的反相結果,而 eq 主要在測試目前物件與 arg0 所參考的物件是否為同一物件. 無論是 Any 中的 ==、!= 或 AnyRef 中的 ==!=eqne 方法,都被宣告為 final,你沒辦法在子類別中重新定義(AnyRef 被宣告為 final,你沒辦法繼承),別以為以下是重新定義 == 方法 : 
  1. class Point(val x: Int, val y: Int) {  
  2.     def ==(that: Point) = this.x == that.x && this.y == that.y  
  3. }  
  4.   
  5. val p1 = new Point(11)  
  6. val p2 = new Point(11)  
  7. println(p1 == p2)         // 顯示 true  
看來好像是對的,但是如果你這麼測試 : 
val p1: AnyRef = new Point(1, 1)
val p2 = new Point(1, 1)
println(p1 == p2)
 // 顯示 false

事實上是,你沒有重新定義 Any 或 AnyRef f的 == 方法,你是定義了一個新的 == 方法,而直接繼承了 Any 與 AnyRef f的 == 方法,所以之前顯示 true 是因為方法被重載了,而你使用的是接受 Point 參數的 == 版本. 因為 Any 與 AnyRef 的 ==!= 都被宣告為 final,你不能重新定義 ==、!= 方法來定義自己的物件相等性。依以上的說明,無論是哪個版本,!= 一定是 == 的反相結果,而 == 都會呼叫 equals() 方法,所以結論是,要定義物件相等性,請重新定義 equals() 方法跟 Java 相同). 
如何正確定義 equals() 需要作些討論,如果你熟悉 Java,可以先看看 Java 物件相等性 中的說明,如果你想要知道如何以 Scala 語法正確定義 equals() 方法,則可以看看 重新定義 equals() 方法

補充說明 : 
[ Java 小學堂 ] Java 世界裡 equals 與 == 的差別

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!