Scala 與 Java 一樣,為避免多重繼承所引起的問題,以及簡化語言的複雜性,採取單一繼承的方式,這也是許多程式語言的方式。
其實,更嚴格來講,不是 Scala 採取與 Java 相同的單一繼承方式,而是「Scala 繼續使用 Java OO 的架構」,這樣講更精確。因為 Scala 根本沒有離開 Java 的範疇。
之前,我們曾提過,Scala 可以與 Java 混用,混用的基礎,除了 Scala 編碼出 JVM 的 bytecode 外,更重要的是,Scala 繼續沿用 Java OO 架構。
我們可以想像「Scala 是 Java 的另一種語法」,這句話是確實的,而且讀者應該把它聽進去。Scala 在 Java 原來架構中擴充,以 JVM 的角度,兩者是混雜在一起。以程式語言的角度, Scala 只是擴充 Java。
我們來看如何擴充?
Java 除了 object 外,為了效能,也支援 8 種支援 primitive type。所以,在 Java 你需要同時面對 primitive type value 與 object。
下圖,是 Java 關於資料型態的示意圖。
我們提過,Scala 為純 OO 的語言。但這不代表 Scala 的效能就不好,或是 Scala 去除掉 Java 的 primitive type。
Scala 是 Pure OO 語言,所以有一套完整的繼承體系。為兼顧效能的問題,Scala 特別為值相關的整合在 Value 值的子系中,而將一般非值的放入 Reference 的子系。Compile 時 compiler會特別為值子系的 instance 編譯為 JVM 對應的資料。
因此,Scala 的手法是包裝,把 Java 的 primitive type 使用 class 把它包裝起來,讓這些 primitive type value,在 object hierarchy 中出現在該出現的地方。
在 Scala 中,把所有的 primitive type 使用一種特殊的 class 包裝起來,這個特殊的 class,在 Scala 稱為 value class。所有 Java 的 primitive type,在 Scala 中都有對應的 class。Value class 有一個共同的 parent class,稱為AnyVal。也就是 AnyVal 是所有 value class 的 root class。
但請注意,這些 value class 是 Scala 世界才可以看到,compile 完後,會變成 Java 的 primitive type,因此不會有效能的問題。我們可以說這些 value class,對應到 Java 的 primitive type。
Scala 的 value class,有一個較特殊的,叫 Unit,我們之前曾經討論過。Unit 是 Java 的 void 對應,但它是一個 value class,請大家不要搞混了,以為它也是一個 reference class。
同樣的,Java 的 Object class,在 Scala 中有一個對應的 class 叫做 AnyRef,代表所有 reference 的 root class。你可以想像,Java 的 Object 就是 AnyRef。在 Scala 世界,Object 這個 class 不再是 object hierarchy 的 root class。
看到此,我們知道,Scala 將 object hierarchy 分成兩大支,一個是 AnyVal,一個是 AnyRef。很顯然,Scala 已經將原來的 object hierarchy 架構擴充開來。AnyRef 這個系列就是原來 Java 的 object hierarchy,而 AnyVal 這個系列就是原來 Java 的 primitive type(再加上 void)。
為整合 AnyRef 與 AnyVal 這兩個大的子系,有一個 Any 的 class 出現,這個 class 是 AnyVal 與 AnyRef 的 parent class,這個 Any 才是 Scala 中的 root class。
上面我們使用「Scala 的什麼東西,對應 Java 的什麼東西」,「對應」這兩個字,其實要更強化一點,對應的意義其實是「把它們當成相同」,我們再進一步解釋:
1. Java 的 int,在 Scala 使用 Int 對應:這代表「Scala 的 Int 就是 Java 的 int,只不過 Scala 把它包裝起來」。同理,所有的 primitive value class 都可這樣看待。
2. Java 的 void,在 Scala 使用 Unit 對應:這代表「Scala 的 Unit 就是 Java 的 void,只不過 Scala 把它包裝起來」。
3. Java 的 Object,在 Scala 使用 AnyRef 對應:這代表「Scala 的 AnyRef 就是 Java 的 Object,兩者可視為同義」

在上圖,可以發現有兩個 class,Null 與 Nothing。Scala 把這兩個 class 加入的原因,是要將 object hierarchy 弄得更完整。
在 OO 語言中,parent class 的變數,可以使用 subclass 的 instance 來指定。所以在 Java,我們可以將任何 instance 指定給 Object 變數,比如,下例是合法的。
Object obj = "abc"; // obj 為 Object 類型的變數,可以使用 "abc" 指定
在 Java,我們可以把 null 值設給 Object 變數。在 Java 中,null 被當成很特殊的 instance 值,所以我們可以「把 null 值設給 Object 變數」,這算是一個特殊規定。
Scala 不希望依循特殊規定, Scala 希望依循的是 OO 的規範。若要達到「讓所有 AnyRef 的變數可以設定為 null」,則 null 必須有某種特性在。注意,在 Scala 中所有東西都是 object,null 也是一個 object。
「讓所有 AnyRef 的變數可以設定為 null」,表示 null 必須是一個特殊 class 的 instance,而該 class 是所有 AnyRef class 的 subclass。
為符合這樣 assignment 的原則,Scala 定義一個新的 class 叫 Null,這個 Null class 是所有 AnyRef subclass 的 subclass。Null class 只有一個 instance,叫做 null。如此一來,null 可以很順利的指定給任何 AnyRef 的變數,而不會破壞 OO 的理論。
請注意,Scala 的 null,不像在 Java 中是一個值,在 Scala 中,它是一個 instance。
Null 是所有 AnyRef subclass 的 subclass,Scala 也針對 Any 這個 class 定義了一個 class,叫 Nothing class,該 class 是所有 Any subclass 的 subclass,這樣整個 Scala 的 object hierarchy 就完整了。
但請注意,Nothing 沒有 instance,因為 AnyRef 的變數 可設定為 null,但 AnyVal 的變數一定是有值,所以不需設為 nothing 這樣的東西,所以 Nothing 並沒有存在 instance 的必要。
Null 與 Nothing 稱為「底層型態」(Bottom Type)。
我們稍微整理一下,Scala 繼續使用 Java 的 object hierarchy,並沒有改變。但 Scala 將原來 Java 的 primitive type 與 object type 加以整合,讓你可以使用純 OO 的角度來看 Scala 的世界。
但請注意,這些擴充與整合,都只出現在 Scala 的世界,並不因此改變 Java 的東西,Java 的東西完全沒有做任何更改。
當 compile 完成,這些 Scala 所擴充的出來的東西,都會編譯為原來 Java 該有的面貌,完全不會改變 Java 的世界。
由於 Scala 只是延續 Java 的架構,並沒有破壞 Java 的東西,所以 Scala 可以與 Java 混合得這麼成功,也因此,我們常說,我們可以把 Scala 看成開發 Java 程式的另一個方法。
沒有留言:
張貼留言