Scala比Java更面向對象的一個方面是Scala沒有靜態成員。替代品是,Scala有單例對象:singleton object。app
當單例對象與某個類共享同一個名稱時,他被稱做是這個類的伴生對象:companion object。你必須在同一個源文件裏定義類和它的伴生對象。類被稱爲是這個單例對象的伴生類:companion class。類和它的伴生對象能夠互相訪問其私有成員。函數
定義單例對象不是定義類型(在Scala的抽象層次上說)spa
類和單例對象間的一個差異是,單例對象不帶參數,而類能夠。由於你不能用new關鍵字實例化一個單例對象,你沒機會傳遞給它參數。每一個單例對象都被做爲由一個靜態變量指向的虛構類:synthetic class的一個實例來實現,所以它們與Java靜態類有着相同的初始化語法。Scala程序特別要指出的是,單例對象會在第一次被訪問的時候初始化。scala
object AbstractTypeTest1 extends Application { def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer = new IntSeqBuffer { type T = List[U] val element = List(elem1, elem2) } val buf = newIntSeqBuf(7, 8) println("length = " + buf.length) println("content = " + buf.element) }
一個伴生對象的示例:code
import scala.collection.mutable.Map class ChecksumAccumulator { private var sum = 0 def add(b: Byte) { 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 } } object Summer { def main(args: Array[String]) { println(ChecksumAccumulator.calculate("Every value is an object.")) } }
輸出爲:orm
-248對象
可是伴生對象如何體現單例的呢?element
class Worker private{ def work() = println("I am the only worker!") } object Worker{ val worker = new Worker def GetWorkInstance() : Worker = { worker.work() worker } } object Job{ def main(args: Array[String]) { for (i <- 1 to 5) { Worker.GetWorkInstance(); } } }
單例模式就控制類實例的個數,經過伴生對象來訪問類的實例就提供了控制實例個數的機會。一個簡單示例:it
不與伴生類共享名稱的單例對象被稱爲孤立對象:standalone object。最多見的就是程序入口:io
class Worker private聲明瞭Worker的首構造函數是私有的,這樣Worker的全部構造函數都不能直接被外部調用,由於全部從構造函數都會首先調用其餘構造函數(能夠是主構造函數,也能夠是從構造函數),結果就是主構造函數是類的惟一入口點。
另外一方面,Worker.GetWorkInstance();有點相似靜態函數調用,但在Scala中這是不對的。Scala會隱式地調用apply來建立一個伴生對象的實例。Scala是一個純粹的面嚮對象語言,不容許有任何破壞對象模型的機制存在,好比類的靜態變量、函數等。