Specific Use of Object Expression and Object Declaration in Kotlin

  • 2021-11-13 18:18:53
  • OfStack

The main difference between an Kotlin object expression and an anonymous inner class in Java is that an anonymous inner class can only specify one parent type, but an object expression can specify 0 ~ N skin types.

1. Object expressions

The syntax format of the object expression is as follows:


object [: 0~N Parent type ]{
  // Class body part of object expression 
}

Object expressions also have the following rules:

An object expression cannot be an abstract class because the system creates an object immediately when it creates an object expression. Therefore, it is not allowed to define object expressions as abstract classes. An object expression cannot define a constructor. But object expressions can define initialization blocks that do what the constructor needs to do. Object expressions can contain inner classes, not nested classes.

package `0705`

interface Outputable {
  fun output(msg: String)
}

abstract class Product(var price: Double) {
  abstract val name: String
  abstract fun printInfo()
}

fun main(args: Array<String>) {
  // Specify 1 Object expression of parent type (interface) 
  var ob1 = object : Outputable {
    override fun output(msg: String) {
      for (i in 1..6) {
        println("<h${i}>${msg}</h${i}>")
      }
    }
  }
  ob1.output(" Just output something ")
  println("-----------------------------------------------")
  // Object expressions that specify zero parent types 
  var ob2 = object {
    // Initialization block 
    init {
      println(" Initialization block ")
    }

    // Attribute 
    var name = "Kotlin"

    // Method 
    fun test() {
      println("test Method ")
    }

    // Can only contain inner classes, not nested classes 
    inner class Inner
  }
  println(ob2.name)
  ob2.test()
  println("-----------------------------------------------")
  // Specifies an object expression of two parent types 
  var ob3 = object : Outputable, Product(1.23) {
    override fun output(msg: String) {
      println(" Output information: ${msg}")
    }

    override val name: String
      get() = " Laser printer "

    override fun printInfo() {
      println(" High-speed aurora printers support automatic double-sided printing! ")
    }
  }
  println(ob3.name)
  ob3.output("Kotlin Learn slowly ")
  ob3.printInfo()
}

Output:

< h1 > Just output something < /h1 >
< h2 > Just output something < /h2 >
< h3 > Just output something < /h3 >
< h4 > Just output something < /h4 >
< h5 > Just output something < /h5 >
< h6 > Just output something < /h6 >
-----------------------------------------------
Initialization block
Kotlin
test method
-----------------------------------------------
Laser printer
Output information: Kotlin learn slowly
High-speed aurora printers support automatic double-sided printing!

Object expressions for Kotlin can be divided into two situations:

The Kotlin compiler recognizes the true type of an object expression when it is within the local scope of a method, or when it is decorated with private. Non-private-decorated object expressions are similar to Java's anonymous inner classes in that the compiler treats the object expression only as if it were inheriting a parent class or implementing an interface. If it has no parent type, the system treats it as an Any type.

package `0705`

class ObjectExprType {
  private val ob1 = object {
    val name: String = "Kotlin"
  }
  internal val ob2 = object {
    val name: String = "Kotlin"
  }
  private fun privateBar()=object {
    val name:String="Java"
  }
  fun publicBar()=object {
    val name:String="Java"
  }
  fun test(){
    //ob1 Yes private Object expression, the compiler can recognize its true type 
    println(ob1.name)
    //ob2 Right and wrong private Object expression, the compiler when it is Any Type 
//    println(ob2.name)
    //privateBar Yes private Function, the compiler can recognize the true type of the object expression it returns 
    println(privateBar().name)
    //publicBar Right and wrong private Function, and the compiler treats the object expression it returns as Any Type 
//    println(publicBar().name)
  }
}

fun main(args: Array<String>) {
  ObjectExprType().test()
}

Output:

Kotlin
Java

The Kotlin compiler recognizes the true type of an private object expression.

Object expressions of Kotlin can access or decorate local variables within their scope.


fun main(args: Array<String>) {
  var a = 20
  var obj = object {

    fun change() {
      println("change() Method to modify variables a Value of ")
      a++
    }
  }
  obj.change()
  println(a)
}

Output:

The change () method modifies the value of the variable a
21

Kotlin's object expressions are enhanced in three ways over Java's anonymous inner classes:

Object expressions can specify multiple parent types The Kotlin compiler can more accurately identify the types of private object expressions in a local scope. Object expressions can access or modify local variables in their scope

2. Object declarations and singleton patterns

The syntax format of object declaration is as follows:


object ObjectName [: 0~N Parent type ]{
  // Class body part of object expression 
}

The syntax of object declarations is similar to that of object expressions, except that object expressions have no name after the object keyword; The object declaration needs to specify a name after the object keyword.

There are also the following differences between the two:

An object expression is an expression that can be assigned to a variable; The object declaration is not an expression and cannot be used for assignment. Object declarations can contain nested classes, not inner classes; Object expressions can contain inner classes, not nested classes. Object declarations cannot be defined within functions and methods; However, object expressions can be nested in other object declarations or non-inner classes.

package `0705`

interface Outputable {
  fun output(msg: String)
}

abstract class Product(var price: Double) {
  abstract val name: String
  abstract fun printInfo()
}

// Specify 1 Object expression of parent type 
object MyObject1 : Outputable {
  override fun output(msg: String) {
    for (i in 1..6) {
      println("<h${i}>${msg}</h${i}>")
    }
  }
}

// Object expressions that specify zero parent types 
object MyObject2 {
  // Initialization block 
  init {
    println(" Initialization block ")
  }

  // Attribute 
  var name = "Kotlin"

  // Method 
  fun test() {
    println("test Method ")
  }

  // Can only contain nested classes, not inner classes 
  class Inner
}

// Specifies an object expression of two parent types 
object MyObject3 : Outputable, Product(1.23) {
  override fun output(msg: String) {
    println(" Output information: ${msg}")
  }

  override val name: String
    get() = " Laser printer "

  override fun printInfo() {
    println(" High-speed aurora printers support automatic double-sided printing! ")
  }
}

fun main(args: Array<String>) {

  MyObject1.output("1 Get up and learn Kotlin")
  println("-----------------------------------------------")
  println(MyObject2.name)
  MyObject2.test()
  println("-----------------------------------------------")
  println(MyObject3.name)
  MyObject3.output("Kotlin That's nice ")
  MyObject3.printInfo()
}

Output:

< h1 > 1 Come and learn Kotlin < /h1 >
< h2 > 1 Come and learn Kotlin < /h2 >
< h3 > 1 Come and learn Kotlin < /h3 >
< h4 > 1 Come and learn Kotlin < /h4 >
< h5 > 1 Come and learn Kotlin < /h5 >
< h6 > 1 Come and learn Kotlin < /h6 >
-----------------------------------------------
Initialization block
Kotlin
test method
-----------------------------------------------
Laser printer
Output message: Kotlin is really good
High-speed aurora printers support automatic double-sided printing!

Object declaration is specially used to implement singleton pattern. The object defined by object declaration is the only instance of this class, and the program can directly access the only instance of this class by the name of object declaration.

3. Associated objects and static members

An object declaration defined in a class can be decorated with companion, so that the object becomes a companion object.

Each class can only define one associated object at most, which is equivalent to the object of external class, and the program can directly call the members of associated objects through external class.


package `0705`

interface CompanionTest {
  fun output(msg: String)
}

class MyClass {
  // Use companion Modified companion object 
  companion object MyObject1 : CompanionTest {
    val name = "name Attribute value "
    override fun output(msg: String) {
      for (i in 1..6) {
        println("<h${i}>${msg}</h${i}>")
      }
    }
  }
}

fun main(args: Array<String>) {
  // Invoke the method of a companion object using the class in which the companion object resides 
  MyClass.output("Kotlin Must learn ")
  println(MyClass.name)
}

Output:

< h1 > Kotlin must be learned < /h1 >
< h2 > Kotlin must be learned < /h2 >
< h3 > Kotlin must be learned < /h3 >
< h4 > Kotlin must be learned < /h4 >
< h5 > Kotlin must be learned < /h5 >
< h6 > Kotlin must be learned < /h6 >
name property value

The main function of an associated object is to simulate static members for its external class, but it is only simulation. The members of an associated object are still instance members of the associated object itself, and do not belong to the external class where the associated object is located.

4. Extension of associated objects

Companion objects can also be extended. If a class has a companion object, Kotlin allows methods and properties to be extended for the companion object.


package `0705`

interface CompanionTest {
  fun output(msg: String)
}

class MyClass {
  // Use companion Modified companion object 
  companion object : CompanionTest {
    val name = "name Attribute value "
    override fun output(msg: String) {
      for (i in 1..6) {
        println("<h${i}>${msg}</h${i}>")
      }
    }
  }
}

// Extending methods for associated objects 
fun MyClass.Companion.test() {
  println(" Extended methods for associated objects ")
}

val MyClass.Companion.foo
  get() = " Attributes extended for accompanying objects "

fun main(args: Array<String>) {
  // Invoke the method of a companion object using the class in which the companion object resides 
  MyClass.output("Kotlin Must learn ")
  println(MyClass.name)
  // Invoke the member extended for the companion object through the class in which the companion object is located 
  MyClass.test()
  println(MyClass.foo)

}

Output:

< h1 > Kotlin must be learned < /h1 >
< h2 > Kotlin must be learned < /h2 >
< h3 > Kotlin must be learned < /h3 >
< h4 > Kotlin must be learned < /h4 >
< h5 > Kotlin must be learned < /h5 >
< h6 > Kotlin must be learned < /h6 >
name attribute value
Extended methods for associated objects
Attributes extended for accompanying objects


Related articles: