類別階層


下圖為Scala的類別階層示意圖:



Scala中所有的類別最頂層的父類別為 scala.Any,其定義了所有物件都要擁有的方法:
final def ==(arg0 : Any) : Boolean 
final def !=(arg0 : Any) : Boolean 
final def isInstanceOf[T0] : Boolean 
final def asInstanceOf[T0] : T0
def equals(arg0 : Any) : Boolean
def hashCode : Int
def toString : java.lang.String

scala.Any下主要區分為兩個子類別:scala.AnyRef  與 scala.AnyVal

在Scala中所有自定義的類別特徵或單例物件,都是scala.AnyRef的子類別(實例),如果你在定義一個類別時,沒有指定父類別,則預設就是繼承自scala.AnyRef,而且所有自定義的類別,都會自動具有 scala.ScalaObject 標示特徵(Marker trait)

若是以Java為平台時,在Scala的型態系統中,將所有Java類別視作是scala.AnyRef的子類別(在Java平台中,java.lang.Object為所有類別的父類別,也就是,scala.AnyRef對應於java.lang.Object),其與Scala類別的差別在於,Java類別並不會具有scala.ScalaObject特徵。

scala.ScalaObject 的目的是定義由編譯器實作的方法。例如若你定義一個類別:
class Some

若是在Java平台上,將這個類別編譯為Some.class檔後,使用javap可以看到:
public class Some extends java.lang.Object implements scala.ScalaObject{
    public Some();
    public int \$tag()       throws java.rmi.RemoteException;
}

目前來說,Scala的類別編譯為.class檔後,僅包括單一個\$tag()方法,其實作是為了增加模式匹配(Pattern match)的效率。若是以Java為平台時,Scala類別可與Java類別互操作,像是Java SE標準API。在Scala中定義的類別,與Java所定義的類別,在編譯過後的差別,在於有無實作scala.ScalaObject。

scala.AnyVal則是所有值型態(Value type)的 父類別,scala.AnyVal有固定數量的子類別,也就是你在上圖中所看到scala.AnyVal下的所有子類別,你寫下1、0.3、true等這 些數值時,在Scala中都是物件,都會有相對應的scala.Int、scala.Double、scala.Boolean等型態對應,你不能直接實 例化scala.AnyVal下的類別,底層系統沒有將值實作為物件時,例如Java,scala.AnyVal下的子類別用以在Scala中將值以物件的方式描述。

Scala中有所謂底層型態(Bottom type),用以處理一些角落情況(Corner case)。由於Scala中,所有的東西都是物件,既然是物件就會有對應的類別,就算是null也是物件,而null對應的型態則為 scala.Null(null是scala.Null的唯一實例)。

在定義變數時,你可以將變數參考至null物件,例如:
val x: String = null

null是scala.Null的實例,這句話要成立,表示scala.Null是java.lang.String的子類別?是的!不僅是java.lang.String,在Scala的型態系統中,scala.Null是所有自定義類別的最底層子類別,也就是說,任何scala.AnyRef的子類別,其最底層子類別一定是scala.Null,也因此,你可以讓任何型態的變數參考到null。

注意!上面所說的是,任何scala.AnyRef的子類別,其最底層子類別一定是scala.Null,所以scala.Null不是scala.AnyVal的底層子類別,所以你不可以這麼作:
val x: Int = null    // 編譯錯誤

null的型態是scala.Null,但scala.Null不是scala.Int的子類別,上面這句話不成立,所以編譯錯誤。

另一個底層型態為 scala.Nothing在Scala的型態系統中,所有類別,也就是所有scala.Any下的類別,包括scala.AnyRef與scala.AnyVal,其最底層子類別為 scala.Nothing。scala.Nothing 沒有實例,這個型態存在主要的目的,在於象徵一種異常終止,一個例子如下:
val input: String = if(args.length != 0) args(0) 
else throw new IllegalArgumentException
println(input)

在Scala 中,if..else會有傳回值,input的型態為String,如果使用者有提供引數,則將第一個引數設給input參考,否則丟出例外,問題是若丟 出例外,那麼if..else的傳回值會是什麼型態?在Scala中,若丟出例外,是一種異常終止,標示的傳回型態會是scala.Nothing。若傳回的型 態是scala.Nothing,上面的程式可以成立,表示scala.Nothing是String的子類別,事實上,scala.Nothing是所 有類別的最底層子類別。

scala.Nothing沒有實例,在程式中你會寫下它的情況,以下範例可能會是一種:
trait Error {
def error(msg: String): Nothing
}

object Logger extends Error {
def error(msg: String) = {
println(msg)
throw new IllegalArgumentException(msg)
}
}

val input = if(args.length != 0) args(0) else Logger.error("請提供引數")
println(input)