Companion Objects and Companion Classes

In the previous article, some people may have noticed that the main method does not have the static keyword of java, and the class that runs the main method defines object. The name of the class defined by object and the class defined by class can still be the same.
For example, class ScalaObject and object ScalaObject, we can say that object ScalaObject is a companion object of class ScalaObject, and class ScalaObject is a companion class of object ScalaObject. Companion objects and companion classes can mutually access private properties and methods.
Define the properties and methods of the companion object in scala:

object ScalaObject2 {
  var str: String = "str"

  def fun(): Unit = {
    println("fun")
  }
}

After compiling, you will see two class files, ScalaObject2 and ScalaObject2$.
ScalaObject2 is decompiled as follows. There are three static methods, one is the fun we defined above, and the other is the set and get methods of str. ScalaObject2.str calls the get method, and ScalaObject2.str="str2" calls the set method.
ScalaObject2..MODULE$ can be called directly in static, so we know that ScalaObject2..MODULE$ is also static.
image.png
ScalaObject2$ is decompiled as follows. From here, it can be seen that it is actually a singleton object. The constructor is decorated with private, and then points to MODULE$ with this, so that MODULE$ provides methods to the outside world.
image.png
In the following example, str is a private property of the companion class ScalaObject. In the companion object ScalaObject, it can be directly accessed, so the companion object and the companion class can mutually access private properties and methods.

class ScalaObject {
  private var str: String = "str"
}

object ScalaObject {
  def main(args: Array[String]): Unit = {
    val scalaObject = new ScalaObject()
    println(scalaObject.str)
  }
}

Singleton

Singleton pattern similar to java:
First, the constructor is private by default. At this time, the object cannot be created directly through the constructor. Then, in the companion object, declare a method to create this object. Since the companion object and the companion class can call each other private methods, it is possible Create this object through the constructor.

object ScalaObject3 {
  private val scalaObject3: ScalaObject3 = new ScalaObject3

  def getInstance(): ScalaObject3 = {
    scalaObject3
  }
}

class ScalaObject3 private() {

}

Then create a singleton in Test. It is not possible to pass new directly, so it is obtained through the companion object. After running, you can see that the two addresses are the same.

object Test {
  def main(args: Array[String]): Unit = {
    //new ScalaObject3()//erro
    val scalaObject1 = ScalaObject3.getInstance()
    val scalaObject2 = ScalaObject3.getInstance()
    println(scalaObject1)
    println(scalaObject2)
  }
}

apply

We define the apply method in the companion object, and then directly category + parameters (there may be no parameters), and actually call the apply method of the companion object.
For example, in the following example, directly calling ScalaObject4("hello") actually calls the ScalaObject4.apply method, so apply can be omitted.

object Test4 {
  def main(args: Array[String]): Unit = {
    ScalaObject4("hello")
    ScalaObject4.apply("hello")
  }
}

object ScalaObject4 {
  def apply(str: String): Unit = {
    println(str)
  }
}

The other is that the new keyword can be omitted. In the following example, the constructor of ScalaObject5 is private, so it is not possible to directly new an object. ScalaObject5 is an instance of ScalaObject5 returned by calling the apply method.
For example, List(1,2,3) is actually calling the apply method.

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{

}

大军
847 声望183 粉丝

学而不思则罔,思而不学则殆


引用和评论

1 篇内容引用
0 条评论