研究一下 主构造函数、次构造函数、init代码块、companion object 的执行顺序
直接看示例:
class User constructor(val temp: String) {
var name = "aaa"
get() = temp
init {
println("------------------ 111 $name")
}
companion object {
init {
println("------------------ 222")
}
}
}
执行 User("bbb") 输出:
222
111 bbb
得出结论:
-
伴生对象在类加载的时候就开始初始化,执行自己内部的 init函数;
-
优先级为:companion object init > class init。
修改示例:
class User constructor(val temp: String) {
var name = "aaa"
get() = temp
init {
println("------------------ 111 $name")
}
companion object {
val user = User("ccc")
init {
println("------------------ 222 ${user.name}")
}
}
}
执行 User("bbb") 输出:
111 ccc
222 ccc
111 bbb
得出结论:
- 伴生对象在类加载的时候就开始初始化,并且只初始化一次,类似java类的 static静态代码块;
- 当初始化伴生对象时,如果其有成员变量生成User对象,会优先执行成员变量的初始化,此时会优先执行User的 init函数;
- 再执行伴生对象内部的 init函数;
- 最后再执行User("bbb") 创建User对象的过程,执行其 init函数;
- 如果class和companion object有多个 init函数,则它们按顺序依次执行;
- 注意:成员变量不能在 init函数之后申明,编译器会报错。
那如果class里还有次构造函数呢?主构造函数、次构造函数、init函数又是按什么顺序执行的呢?
看个示例:
class User constructor(val temp: String) {
var name = "aaa"
get() = temp
constructor(temp: String, age: Int) : this(temp){
println("------------------ 333 ${name}")
}
init {
println("------------------ 111 $name")
}
companion object {
val user = User("ccc",3)
init {
println("------------------ 222 ${user.name}")
}
}
}
执行 User("bbb") 输出:
111 ccc
333 ccc
222 ccc
111 bbb
- 其实道理都是一样的,无论有多少个构造函数,也无论有多少个init函数,伴生对象都会优先执行,并且只执行一次,所以会按顺序初始化伴生对象里的成员变量及 init函数;
- 如果伴生对象的成员变量是创建User()对象,则就先去执行User的创建,即执行User的 init函数和构造函数;
- 所以先输出了init函数的:111 ccc,看到name已经被赋值为:ccc,即优先执行了主构造函数,再执行了init函数;
- 再输出了次构造函数的:333 ccc;
- 伴生对象成员变量初始化完成后,再执行伴生对象的 init函数,输出了:222 ccc;
- 最后再执行 User("bbb") ,又执行了一次class的init函数,输出了:111 bbb。
假设此时执行的是User("bbb",1),则最后输出的是:
111 ccc
333 ccc
222 ccc
111 bbb
333 bbb
又重复按顺序执行了class的主构造函数 > init函数 > 次构造函数。
总结:
- 伴生对象在类加载的时候就开始初始化,并且只初始化一次,类似java类的 static静态代码块;会按顺序初始化伴生对象里的成员变量及 init函数;
- class类里的执行顺序是:主构造函数 > init函数(多个按顺序执行) > 次构造函数。