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是一个纯粹的面向对象语言,不容许有任何破坏对象模型的机制存在,好比类的静态变量、函数等。