前面提到 Scala 比 Java 更加面向對象,這是因為 Scala 不允許類保護靜態(tài)元素(靜態(tài)變量或靜態(tài)方法)。在 Scala 中提供類似功能的是成為“Singleton(單例對象)”的對象。在 Scala 中定義 Singleton 對象的方法除了使用 object,而非 class 關鍵字外和類定義非常類似,下面例子創(chuàng)建一個 ChecksumAccumulator 對象:
object ChecksumAccumulator {
private val cache = Map [String, Int] ()
def calculate(s:String) : Int =
if(cache.contains(s))
cache(s)
else {
val acc=new ChecksumAccumulator
for( c <- s)
acc.add(c.toByte)
val cs=acc.checksum()
cache += ( s -> cs)
cs
}
}
這個對象和上一篇創(chuàng)建的類 ChecksumAccumulator 同名,這在 Scala 中把這個對象成為其同名的類的“伴侶”對象( Companion object )。 如果你需要定義的類的 companion 對象,Scala 要求你把這兩個定義放在同一個文件中。類和其 companion 對象可以互相訪問對方的私有成員。
如果你是 Java 成員,可以把 Singleton 對象看成以前 Java 定義靜態(tài)成員的地方。你可以使用類似 Java 靜態(tài)方法的方式調用 Singleton 對象的方法,比如下面為這個例子完整的代碼:
import scala.collection.mutable.Map
class ChecksumAccumulator{
private var sum=0
def add(b:Byte) :Unit = sum +=b
def checksum() : Int = ~ (sum & 0xFF) +1
}
object ChecksumAccumulator {
private val cache = Map [String, Int] ()
def calculate(s:String) : Int =
if(cache.contains(s))
cache(s)
else {
val acc=new ChecksumAccumulator
for( c <- s)
acc.add(c.toByte)
val cs=acc.checksum()
cache += ( s -> cs)
cs
}
}
println ( ChecksumAccumulator.calculate("Welcome to Scala Chinese community"))
Scala 的 singleton 對象不僅限于作為靜態(tài)對象的容器,它在 Scala 中也是頭等公民,但僅僅定義 Singleton 對象本身不會創(chuàng)建一個新的類型,你不可以使用 new 再創(chuàng)建一個新的 Singleton 對象(這也是 Singleton 名字的由來),此外和類定義不同的是,singleton 對象不可以帶參數(shù)(類定義參數(shù)將在后面文章介紹)。
回過頭來看看我們的第一個例子 “Hello World“。
object HelloWorld {
def main(args: Array[String]) {
println("Hello, world!")
}
}
這是一個最簡單的 Scala 程序,HelloWorld 是一個 Singleton 對象,它包含一個 main 方法(可以支持命令行參數(shù)),和 Java 類似,Scala 中任何 Singleto 對象,如果包含 main 方法,都可以作為應用的入口點。
在這里要說明一點的是,在 Scala 中不要求 public 類定義和其文件名同名,不過使用和 public 類和文件同名還是有它的優(yōu)點的,你可以根據(jù)個人喜好決定是否遵循 Java 文件命名風格。
最后提一下 Scala 的 trait 功能,Scala 的 trait 和 Java 的 Interface 相比,可以有方法的實現(xiàn)(這點有點像抽象類,但如果是抽象類,就不會允許繼承多個抽象類)。Scala 的 Trait 支持類和 Singleton 對象和多個 Trait 混合(使用來自這些 Trait 中的方法,而不時不違反單一繼承的原則)。
Scala 為 Singleton 對象的 main 定義了一個 App trait 類型,因此上面的例子可以簡化為:
object HelloWorld extends App{
println("Hello, world!")
}
這段代碼就不能作為腳本運行,Scala 的腳本要求代碼最后以表達式結束。因此運行這段代碼,需要先編譯這段代碼:
scalac Helloworld.scala
編譯好之后,運行該應用
scala HelloWord
注意
: Scala 提供了一個快速編譯代碼的輔助命令 fsc (fast scala compliler) ,使用這個命令,只在第一次使用 fsc時啟動 JVM,之后 fsc 在后臺運行,這樣就避免每次使用 scalac 時都要載入相關庫文件,從而提高編譯速度。