在 Kotlin 中,一个类可以有一个 primary constructor 和任意数量的 secondary constructors。与 Java 的不同之处在于,Kotlin 的 primary constructor 在类头中声明,并可以包含参数和修饰符。Secondary constructors 必须调用另一个 secondary constructor、primary constructor,或者超类的构造函数(通过关键字 super)。
关键特点:
: super(...) 调用它。super(...) 或另一个 secondary/primary constructor 调用基类。使用继承的示例:
open class A(val a: Int) { constructor(a: Int, str: String) : this(a) { println("A中的二级构造函数: $str") } } class B : A { constructor(a: Int) : super(a) { println("B中的二级构造函数") } constructor(a: Int, s: String) : super(a, s) { println("B中的二级构造函数 #2") } }
与 Java 的方法有何不同:
在 Kotlin 中,如果基础类只有特定构造函数,是否可以在不明确调用超类构造函数的情况下创建子类?
答案: 不可以,与 Java 不同,在 Kotlin 中必须调用超类构造函数,并且明确在类头或在关键字 : super() 后指定。
错误示例:
open class Base(val x: Int) class Derived : Base // 编译错误!
故事
在微服务项目中,迁移到 Kotlin 后忘记了显式指定父构造函数:未调用带必需参数的超类构造函数,服务无法编译,必须重构签名。
故事
Android 项目具有深层次的层次结构(Activity → BaseActivity → CustomActivity),添加 secondary constructor 时丢失了参数,最终调用了错误的基构造函数,部分字段保持为 null,应用程序在运行时因 NPE 崩溃。
故事
在开源库代码中,子类的 secondary constructor 偶然绕过了 primary constructor,导致两个不同的初始化路径:有时字段被初始化,有时没有。这个错误直到经过很长时间和复杂的 bug 报告才被发现。