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