主构造函数、次构造函数、init函数

141 阅读2分钟

研究一下 主构造函数、次构造函数、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函数(多个按顺序执行) > 次构造函数。