2015-07-21 56 views
8

只見從圖書館借了一些代碼:爲什麼斯卡拉類需要明確地擴展AnyRef

trait A extends scala.AnyRef 
trait B extends scala.AnyRef with A 

爲什麼A需要明確地擴展AnyRef?是不是所有的類都已經從AnyRef隱含派生出來?

爲什麼B需要延長AnyRef即使A已經做到了這一點?有什麼區別上面的代碼更改爲:

trait A 
trait B extends A 
+2

它是什麼庫? –

+0

一個衆所周知的圖書館。不想在這裏提及這個名字。 – jiangok

+4

爲什麼不能?有些背景可能有助於弄清楚是否有任何理由。 –

回答

7

我會說沒有任何區別。

scala documentation

用戶定義的類默認定義引用類型;即它們總是(間接)子類scala.AnyRef

爲了進一步證明這一點

scala> trait A 
defined trait A 

scala> trait B extends A 
defined trait B 

scala> val a = new A { } 
a: A = [email protected] 

scala> val b = new B { } 
b: B = [email protected] 

scala> a.isInstanceOf[AnyRef] 
res4: Boolean = true 

scala> b.isInstanceOf[AnyRef] 
res7: Boolean = true 
2

您沒有明確擴展AnyRef。 AnyRef相當於Java的Scala中的對象。 通過創建類的實例,該實例將隱式擴展AnyRef,而不管它是否在其某個超類中被明確提及。

下面的代碼僅僅是創建一個匿名類,因此也延伸AnyRef含蓄:

trait A 
val a = new A { } 

這裏是scala-lang.org的解釋:

所有的超類scala.Any有兩個直接的子類scala.AnyVal和scala.AnyRef表示兩個不同的類世界:值類和引用類。所有的值類都是預定義的;它們對應於Java類語言的基本類型。所有其他類定義引用類型。用戶定義的類默認定義引用類型;即它們總是(間接)子類scala.AnyRef。 Scala中的每個用戶定義的類都隱式擴展了特徵scala.ScalaObject。運行Scala的基礎結構中的類(例如Java運行時環境)不會擴展scala.ScalaObject。如果在Java運行時環境中使用Scala,則scala.AnyRef對應於java.lang.Object。請注意,上面的圖表還顯示了在值類之間的稱爲視圖的隱式轉換。下面是一個說明,這兩個數字,字符,布爾值,和函數是對象就像所有其他對象的例子:

http://docs.scala-lang.org/tutorials/tour/unified-types.html

由於Scala的2.10還可以擴展AnyVal。來自scala-lang.org:

AnyVal是所有值類型的根類,它描述了未在底層主機系統中實現爲對象的值。 在Scala 2.10之前,AnyVal是一個密封的特徵。但是,從Scala 2.10開始,可以定義AnyVal的一個子類,稱爲用戶定義的值類,它由編譯器專門處理。正確定義的用戶值類提供了一種方法,通過在運行時避免對象分配以及用靜態方法調用替換虛擬方法調用來提高用戶定義類型的性能。

+0

可能值得添加關於後來添加的「AnyVal」的信息,這使得「他們總是......子類scala.AnyRef」部分不完全正確。 – Suma

+0

通過使用isInstanceOf進行檢查,您將看到用戶創建的類實際上也擴展了AnyRef。這很奇怪,但它是如何實施的。 –

+0

這不完全正確。只是碰巧'isInstanceOf'完全依賴於jvm運行時類型,因此泄漏的信息幾乎是一個實現細節。當你在某個值類實例上調用'isInstanceOf'時,該值首先被裝箱,當然這個盒裝實例擴展了'Object'(又名'AnyRef')。你可以把它稱爲一個錯誤,一個令人驚訝的行爲,或者一個明顯的[泄漏抽象](https://en.wikipedia.org/wiki/Leaky_abstraction)。但是你不能說AnyVal是AnyRef。 –