在 Kotlin 中,构造方法分为主构造方法(Primary Constructor)和次构造方法(Secondary Constructor)。
1 主构造方法
主构造方法是类的核心构造方法,直接在类头声明,位于类名之后。
1.1 基本语法
kotlin
class Person constructor(val name: String, val age: Int) {
// 类体
}
如果主构造方法没有注解或可见性修饰符,constructor
关键字可以省略:
kotlin
class Person(val name: String, val age: Int) {
// 类体
}
1.2 特点
1.2.1 属性声明
参数直接作为属性:可通过 val
或 var
将主构造函数的参数声明为类的属性。
kotlin
class Person(val name: String, age: Int) {
// name 是属性,age 是构造方法参数
}
1.2.2 构造方法参数的作用域
主构造方法的参数可以在类体中直接使用,但未声明 val
/ var
的参数仅在 init
代码块和属性初始化器中可见。
kotlin
class User(private val id: String, name: String, age: Int) {
// id 是类属性,在任何地方都可以用
// name、age 仅在 init 代码块和属性初始化器中可见
val displayName = "[$id] $name"
init {
println("age = $age")
}
}
属性初始化器是用于在声明属性时直接赋值的语法,它允许在类体或主构造函数中直接为属性设置初始值。
属性初始化器可以在以下两种场景中使用:
- 主构造函数中声明属性并初始化;
- 类体中可以直接初始化属性;
kotlin
// 通过主构造函数参数声明属性并初始化
class User(val name: String = "Unknown", var age: Int = 0)
class User {
val name: String = "Unknown" // 属性初始化器
val age: Int = 0 // 属性初始化器
}
1.2.3 初始化代码
使用 init
代码块执行额外的初始化逻辑。
kotlin
class User(name: String, age: Int) {
val formattedName: String
init {
formattedName = "Mr./Ms. $name"
println("Person initialized: $formattedName")
}
}
1.2.4 可见性修饰符
主构造函数的可见性默认是 public
,可显式指定:
kotlin
class User private constructor(val name: String) // 私有构造方法
2 次构造方法(Secondary Constructor)
次构造方法通过 constructor
关键字在类体内定义,必须直接或间接调用主构造函数。
2.1 基本语法
kotlin
class Person(val name: String) {
var age: Int = 0
// 次构造方法必须直接或间接委托给主构造方法
constructor(name: String, age: Int) : this(name) {
this.age = age
}
}
2.2 注意事项
2.2.1 必须委托
每个次构造函数必须通过 this()
调用主构造函数或其他次构造函数,确保所有初始化路径都经过主构造函数:
kotlin
class User {
constructor(name: String) : this(name, 0) // 错误:没有主构造方法
constructor(name: String, age: Int) // 如果没有主构造方法,次构造方法无需委托
}
2.2.2 初始化顺序
主构造函数的参数初始化 ---> init
代码块 ---> 次构造函数体:
kotlin
class User(val name: String) {
init {
println("主构造方法初始化")
}
constructor(name: String, age: Int) : this(name) {
println("次构造方法执行")
}
}
fun main() {
User("Eileen", 34)
}
// 主构造方法初始化
// 次构造方法执行
2.2.3 避免与主构造方法参数冲突
次构造方法的参数名应避免与主构造方法的属性名重复:
kotlin
class User(val name: String) {
constructor(name: String, age: Int) : this(name) {
// 此处的 name 参数会屏蔽类的 name 属性
}
}
3 初始化顺序
- 主构造函数参数初始化;
- 类属性按声明顺序初始化;
init
块按出现顺序执行;- 次构造函数执行;
kotlin
class User(val name: String = "Eileen") {
val a = println("a 初始化")
init {
println("init 1")
}
val b = println("b 初始化")
init {
println("init 2")
}
}
fun main() {
User()
}
// a 初始化 -> init 1 -> b 初始化 -> init 2
4 默认参数替代次构造方法
Kotlin 支持构造函数参数默认值,可减少构造函数的数量:
kotlin
class User(
val name: String,
val age: Int = 0, // 默认参数
val country: String = "Unknown"
)
fun main() {
val user1 = User("Eileen")
val user2 = User("Eileen", 34)
val user3 = User("Eileen", 34, "China")
}
Java 互操作性:如果需要在 Java 中调用带默认参数的构造方法,需添加 @JvmOverloads
注解:
kotlin
class Person @JvmOverloads constructor(
val name: String,
val age: Int = 0,
val country: String = "Unknown"
)
5 继承中的构造方法
5.1 子类必须初始化父类构造方法
子类的主构造方法需初始化父类的主构造方法:
kotlin
open class User(val name: String)
class Student(name: String) : User(name)
如果父类只有次构造方法(无主类构造方法),子类需通过 super
调用父类的某个次构造方法:
kotlin
open class User {
constructor(name: String) {
}
}
class Student : User {
constructor(name: String) : super(name)
}
5.2 抽象类的构造方法
抽象类的构造函数可由子类实现:
kotlin
abstract class User(val name: String)
class Student(name: String, val age: Int) : User(name)
6 数据类中的构造方法
数据类的主构造方法必须至少有一个参数,且所有的参数必须标记为 val
或 var
:

7 总结
场景 | 注意事项 |
---|---|
主构造方法 | 参数可声明为属性,初始化顺序严格,支持默认参数替代次构造方法 |
次构造方法 | 必须委托主构造方法,代码体在类初始化后执行 |
继承 | 子类必须初始化父类构造方法,优先使用主构造方法 |
默认参数 | 替代次构造方法,需要 @JvmOverloads 支持 Java 调用 |
初始化顺序 | init 块和属性初始化按照代码顺序执行,次构造方法体最后执行 |