Kotlin 构造函数关键字
最后修改于 2025 年 4 月 19 日
Kotlin 提供了通过构造函数初始化类的灵活方式。 constructor 关键字用于定义主构造函数和次构造函数。本教程通过实际示例深入探讨构造函数。
基本定义
在 Kotlin 中,构造函数是一个特殊的成员函数,用于初始化类的实例。有两种类型:主构造函数(在类头中定义)和次构造函数(在类体中定义)。对于没有注解或可见性修饰符的主构造函数,constructor 关键字是可选的。
主构造函数
主构造函数在类头中声明。 它可以包含成为类属性的参数。 如果没有注解或修饰符,这里的构造函数关键字是可选的。
package com.zetcode
class Person constructor(val name: String, val age: Int)
fun main() {
val person = Person("John Doe", 30)
println("${person.name} is ${person.age} years old")
// Output: John Doe is 30 years old
}
此示例显示了一个带有两个参数的主构造函数。 val 关键字使它们成为不可变属性。 我们创建一个 Person 实例并直接访问其属性。
没有关键字的主构造函数
当主构造函数没有注解或可见性修饰符时,为了更简洁的语法,可以省略 constructor 关键字。
package com.zetcode
class Person(val name: String, val age: Int)
fun main() {
val person = Person("Jane Smith", 25)
println("${person.name} is ${person.age} years old")
// Output: Jane Smith is 25 years old
}
这是声明主构造函数最常见的方式。 参数会自动成为类属性。 语法简洁明了,同时提供相同的功能。
带有初始化块的主构造函数
init 块允许在创建对象期间执行代码。它在评估主构造函数参数之后但在任何次构造函数之前运行。
package com.zetcode
class Person(name: String, val age: Int) {
val name: String
init {
this.name = name.capitalize()
println("Person initialized: $name")
}
}
fun main() {
val person = Person("alice", 28)
println("${person.name} is ${person.age}")
// Output: Person initialized: alice
// Alice is 28
}
在这里,我们在将 name 参数分配给属性之前,在 init 块中处理它。 init 块可以包含类所需的任何初始化逻辑。 多个 init 块按出现的顺序执行。
次构造函数
次构造函数使用 constructor 关键字在类体中定义。如果存在主构造函数,它们必须委托给主构造函数。
package com.zetcode
class Person(val name: String, val age: Int) {
constructor(name: String) : this(name, 0) {
println("Secondary constructor used")
}
}
fun main() {
val person1 = Person("Bob", 40)
val person2 = Person("Charlie")
println("${person2.name} is ${person2.age}")
// Output: Secondary constructor used
// Charlie is 0
}
次构造函数提供默认年龄 0。它必须使用 this 调用主构造函数。 次构造函数对于多个初始化路径很有用,同时保持单个主初始化。
带有可见性修饰符的构造函数
指定可见性修饰符时,需要 constructor 关键字。这控制了可以从其他代码访问构造函数的方式。
package com.zetcode
class Person private constructor(val name: String) {
companion object {
fun create(name: String): Person {
return Person(name)
}
}
}
fun main() {
val person = Person.create("Admin")
println(person.name) // Output: Admin
}
这里,主构造函数是私有的,因此必须通过伴生对象中的工厂方法创建实例。 这是一种用于控制对象创建的常见模式,例如在单例实现中。
多个次构造函数
一个类可以有多个次构造函数,每个构造函数都提供了不同的初始化对象的方式。 所有构造函数最终都必须委托给主构造函数。
package com.zetcode
class Person(val name: String, val age: Int) {
constructor(name: String) : this(name, 0)
constructor(age: Int) : this("Anonymous", age)
}
fun main() {
val person1 = Person("Dave")
val person2 = Person(35)
println("${person1.name} is ${person1.age}")
println("${person2.name} is ${person2.age}")
// Output: Dave is 0
// Anonymous is 35
}
此类提供了三种创建实例的方式:同时使用 name 和 age,仅使用 name(默认年龄),或仅使用 age(默认名称)。 每个次构造函数都提供不同的默认值,同时保持一致性。
带有默认值的构造函数
Kotlin 允许为构造函数参数指定默认值,通常不需要次构造函数。 这提供了灵活的初始化选项。
package com.zetcode
class Person(
val name: String = "Guest",
val age: Int = 0
)
fun main() {
val person1 = Person()
val person2 = Person("Eve")
val person3 = Person(age = 30)
println("${person1.name} is ${person1.age}")
println("${person2.name} is ${person2.age}")
println("${person3.name} is ${person3.age}")
// Output: Guest is 0
// Eve is 0
// Guest is 30
}
默认参数允许使用任意参数组合创建对象。 命名参数使跳过参数时的代码更具可读性。 对于更简单的情况,这种方法通常优于多个构造函数。
构造函数的最佳实践
- 首选主构造函数: 尽可能使用带有默认值的主构造函数以获得更简洁的代码。
- 明智地使用 init 块: 将初始化逻辑保持在 init 块中,使其简单并专注于设置。
- 限制次构造函数: 仅在真正需要多个初始化路径时才添加次构造函数。
- 考虑使用工厂函数: 对于复杂的初始化,考虑使用伴生对象工厂函数,而不是使用多个构造函数。
- 使用有意义的默认值: 选择对领域有意义并提供良好默认值的默认值。
来源
本教程深入探讨了 Kotlin 的 constructor 关键字,展示了主构造函数和次构造函数的使用。 我们探讨了各种初始化模式,包括默认值、init 块和可见性修饰符。 正确使用构造函数可以使类设计更易于维护和更灵活。
作者
列出 所有 Kotlin 教程。