什么是Kotlin类初始化语义?

时间:2021-04-19 06:56:39

I haven't been able to find anything in the language definition that explains the initialisation of a class in Kotlin.

我无法在语言定义中找到解释Kotlin中类的初始化的任何内容。

import java.util.Properties

fun main(args: Array<String>) {
    val out = MyClass()
    out.fn()
}

class MyClass {
    private val a = Properties() // 1

    init {
        fn()
    }

    public fun fn() {
        println("Fn called.  a = $a")
    }

    //  private val a = Properties() // 2
}

The results of running this program change depending whether the property is initialised at (1) or at (2).

运行此程序的结果根据属性是在(1)还是在(2)初始化而改变。

I'm surprised that the declaration order is relevant in the language and would like to understand the decisions behind this. My expectation would be that properties are initialised before the constructor body is invoked.

我很惊讶声明顺序与语言相关,并且想要理解这背后的决定。我的期望是在调用构造函数体之前初始化属性。

2 个解决方案

#1


11  

My expectation would be that properties are initialised before the constructor body is invoked.

我的期望是在调用构造函数体之前初始化属性。

Well, init block is not a constructor. It is a different construct which allows you to perform the initialization of the object and they [init blocks] are performed in the declaration order with the property initializers.

好吧,init块不是构造函数。它是一个不同的结构,允许您执行对象的初始化,并且它们[init blocks]在声明顺序中使用属性初始值设定项执行。

Constructors are a different beast ant they are performed after all the properties were initialized and all init blocks were performed. Look at the following example:

构造函数是一个不同的野兽蚂蚁,它们在初始化所有属性并执行所有初始化块后执行。请看以下示例:

class A(val value: Int) {
    constructor(): this(0) {        
        println("Constructor")
    }    

    init {
        println("Init block")
    }
}

fun main(args: Array<String>) {
    val a = A()
}

Output is:

输出是:

Init block  
Constructor

You can place the init block wherever you want: before the constructor or after it; it will always be performed before the A's constructor (secondary constructor, in this example).

您可以将init块放在任何位置:构造函数之前或之后;它总是在A的构造函数(在本例中为辅助构造函数)之前执行。

#2


5  

Simply put: when an instance of a class is created, (almost) firstly runs the constructor of the parent class (if present), then the primary constructor.

简单地说:当创建一个类的实例时,(几乎)首先运行父类的构造函数(如果存在),然后运行主构造函数。

The primary constructor executes code declared in the class body from the top to the bottom. Also the names became available by the same rule:

主构造函数从顶部到底部执行在类体中声明的代码。这些名字也可以通过相同的规则获得:

class Foo(a: String = "might be first"
          val b: String = "second" + a) : Boo(a + b + "third"){
    var c = a + "fourth" + b

    init {print("fifth: $c")}

    val d = "sixth"
    init {print("seventh: the end of the primary constructor"}
}

If you invoke a secondary constructor, then it works after the primary one as it is composed in the chain (similar to invoking the parent constructors).

如果您调用辅助构造函数,那么它在主要构造函数之后工作,因为它在链中组成(类似于调用父构造函数)。

#1


11  

My expectation would be that properties are initialised before the constructor body is invoked.

我的期望是在调用构造函数体之前初始化属性。

Well, init block is not a constructor. It is a different construct which allows you to perform the initialization of the object and they [init blocks] are performed in the declaration order with the property initializers.

好吧,init块不是构造函数。它是一个不同的结构,允许您执行对象的初始化,并且它们[init blocks]在声明顺序中使用属性初始值设定项执行。

Constructors are a different beast ant they are performed after all the properties were initialized and all init blocks were performed. Look at the following example:

构造函数是一个不同的野兽蚂蚁,它们在初始化所有属性并执行所有初始化块后执行。请看以下示例:

class A(val value: Int) {
    constructor(): this(0) {        
        println("Constructor")
    }    

    init {
        println("Init block")
    }
}

fun main(args: Array<String>) {
    val a = A()
}

Output is:

输出是:

Init block  
Constructor

You can place the init block wherever you want: before the constructor or after it; it will always be performed before the A's constructor (secondary constructor, in this example).

您可以将init块放在任何位置:构造函数之前或之后;它总是在A的构造函数(在本例中为辅助构造函数)之前执行。

#2


5  

Simply put: when an instance of a class is created, (almost) firstly runs the constructor of the parent class (if present), then the primary constructor.

简单地说:当创建一个类的实例时,(几乎)首先运行父类的构造函数(如果存在),然后运行主构造函数。

The primary constructor executes code declared in the class body from the top to the bottom. Also the names became available by the same rule:

主构造函数从顶部到底部执行在类体中声明的代码。这些名字也可以通过相同的规则获得:

class Foo(a: String = "might be first"
          val b: String = "second" + a) : Boo(a + b + "third"){
    var c = a + "fourth" + b

    init {print("fifth: $c")}

    val d = "sixth"
    init {print("seventh: the end of the primary constructor"}
}

If you invoke a secondary constructor, then it works after the primary one as it is composed in the chain (similar to invoking the parent constructors).

如果您调用辅助构造函数,那么它在主要构造函数之后工作,因为它在链中组成(类似于调用父构造函数)。