Companion objects and associated classes

In the previous article, you might also have noticed that the main method doesn’t have a static keyword like the Java keyword, and that the class that runs the main method defines an Object. A class defined by Object can have the same name as a class defined by Class. Class ScalaObject and Object ScalaObject, we can say Object ScalaObject is a companion object to Class ScalaObject, Class ScalaObject is a companion class to Object ScalaObject. Companion objects and associated classes can access each other’s private properties and methods. Defining the properties and methods of companion objects in Scala:

object ScalaObject2 {
  var str: String = "str"

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

When compiled, you’ll see two class files, ScalaObject2 and ScalaObject2$.

ScalaObject2 decomiles as follows, where there are three static methods, one for fun as we defined above, and the other for STR’s set and get methods. ScalaObject2.str calls the get method, and scalaObject2.str =”str2″ calls the set method.

Static can call ScalaObject2 directly.. MODULE$, so we know that ScalaObject2… Module $is also static.



ScalaObject2$decomiles as follows, which shows that it is actually a singleton object. The constructor decorates it private, then points to Module $with this to make Module $provide methods to the outside world.



In the following example, STR is a private property of the companion class ScalaObject, in which the companion class ScalaObject is directly accessible, so the companion object and the companion class can access each other’s 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)
  }
}

The singleton

Similar Java singleton pattern: first, the constructor private by default, this is not directly through the constructor to create the object, and then in the associated object, declare a method used to create the object, because the associated objects and associated class can call each other a private method, so it can be through the constructor to create the object.

object ScalaObject3 {
  private val scalaObject3: ScalaObject3 = new ScalaObject3

  def getInstance(): ScalaObject3 = {
    scalaObject3
  }
}

class ScalaObject3 private() {

}

Then create a singleton in Test. You can’t use new directly, so get it from a companion object. When you run it, 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 class the + argument (which may have no arguments), actually calling the apply method on the companion object. For example, in the following example, a direct call to 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)
  }
}

Another option is to omit the new keyword. In the following example, the constructor of ScalaObject5 is private, so it is not possible to simply new an object. ScalaObject5 is an instance of ScalaObject5 returned by calling the apply method. For example, List(1,2,3) calls 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{

}