在前面的文章中,可能也有人注意到main方法並無像java的static關鍵字,並且運行main方法的類定義的是object。object定義的類和class定義的類名字還能夠同樣。
好比class ScalaObject和object ScalaObject,咱們能夠說object ScalaObject是class ScalaObject的伴生對象,class ScalaObject是object ScalaObject的伴生類。伴生對象和伴生類能夠相互訪問私有的屬性和方法。
在scala中定義伴生對象的屬性和方法:java
object ScalaObject2 { var str: String = "str" def fun(): Unit = { println("fun") } }
編譯後會看到有ScalaObject2和ScalaObject2$兩個class文件。
ScalaObject2反編譯以下,這裏有3個靜態方法,一個是咱們上面定義的fun,另一個就是str的set和get方法。ScalaObject2.str就是調用get方法,ScalaObject2.str="str2"就是調用set方法。
在static裏能直接調用ScalaObject2..MODULE$,因此咱們知道ScalaObject2..MODULE$也是靜態的。
ScalaObject2$反編譯以下,從這裏能夠看出,他其實是一個單例對象。構造函數用private修飾,而後又用this指向MODULE$,讓MODULE$對外提供方法。
在下面的例子中,str是伴生類ScalaObject的私有屬性,在伴生對象ScalaObject中,是能夠直接訪問的,因此伴生對象和伴生類能夠相互訪問私有的屬性和方法。app
class ScalaObject { private var str: String = "str" } object ScalaObject { def main(args: Array[String]): Unit = { val scalaObject = new ScalaObject() println(scalaObject.str) } }
相似java的單例模式:
首先構造器默認private的,此時是不能直接經過構造器來建立這個對象,而後在伴生對象中,聲明一個方法用於建立這個對象,因爲伴生對象和伴生類能夠互相調用私有方法,因此是能夠經過構造器來建立這個對象。函數
object ScalaObject3 { private val scalaObject3: ScalaObject3 = new ScalaObject3 def getInstance(): ScalaObject3 = { scalaObject3 } } class ScalaObject3 private() { }
而後在Test中建立一個單例,直接經過new是不行的,因此經過伴生對象來獲取。運行後,能夠看到兩個地址是同樣的。this
object Test { def main(args: Array[String]): Unit = { //new ScalaObject3()//erro val scalaObject1 = ScalaObject3.getInstance() val scalaObject2 = ScalaObject3.getInstance() println(scalaObject1) println(scalaObject2) } }
咱們在伴生對象中定義apply方法,而後直接類目+參數(有可能無參),實際上調用的是伴生對象的apply方法。
好比在下面例子中,直接調用ScalaObject4("hello")實際上調用的是ScalaObject4.apply方法,因此apply是能夠省略的。spa
object Test4 { def main(args: Array[String]): Unit = { ScalaObject4("hello") ScalaObject4.apply("hello") } } object ScalaObject4 { def apply(str: String): Unit = { println(str) } }
另一個就是能夠省略到new關鍵字。下面例子中,ScalaObject5的構造器是私有的,因此直接new一個對象是不行的,ScalaObject5是調用apply方法才返回的ScalaObject5實例。
好比List(1,2,3),其實就是調用apply方法。scala
object Test5 { def main(args: Array[String]): Unit = { val scalaObject = ScalaObject5 //val scalaObject1 = new ScalaObject5 erro } } object ScalaObject5 { def apply(): ScalaObject5 = { new ScalaObject5 } } class ScalaObject5 private{ }