伴生对象和伴生类

在后面的文章中,可能也有人留神到main办法并没有像java的static关键字,而且运行main办法的类定义的是object。object定义的类和class定义的类名字还能够一样。
比方class ScalaObject和object ScalaObject,咱们能够说object ScalaObject是class ScalaObject的伴生对象,class ScalaObject是object ScalaObject的伴生类。伴生对象和伴生类能够互相拜访公有的属性和办法。
在scala中定义伴生对象的属性和办法:

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中,是能够间接拜访的,所以伴生对象和伴生类能够互相拜访公有的属性和办法。

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是不行的,所以通过伴生对象来获取。运行后,能够看到两个地址是一样的。

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办法,而后间接类目+参数(有可能无参),实际上调用的是伴生对象的apply办法。
比方在上面例子中,间接调用ScalaObject4("hello")实际上调用的是ScalaObject4.apply办法,所以apply是能够省略的。

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办法。

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{}