ZetCode

Kotlin 构造函数关键字

最后修改于 2025 年 4 月 19 日

Kotlin 提供了通过构造函数初始化类的灵活方式。 constructor 关键字用于定义主构造函数和次构造函数。本教程通过实际示例深入探讨构造函数。

基本定义

在 Kotlin 中,构造函数是一个特殊的成员函数,用于初始化类的实例。有两种类型:主构造函数(在类头中定义)和次构造函数(在类体中定义)。对于没有注解或可见性修饰符的主构造函数,constructor 关键字是可选的。

主构造函数

主构造函数在类头中声明。 它可以包含成为类属性的参数。 如果没有注解或修饰符,这里的构造函数关键字是可选的。

PrimaryConstructor.kt
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 关键字。

SimplePrimaryConstructor.kt
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 块允许在创建对象期间执行代码。它在评估主构造函数参数之后但在任何次构造函数之前运行。

InitBlock.kt
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 关键字在类体中定义。如果存在主构造函数,它们必须委托给主构造函数。

SecondaryConstructor.kt
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 关键字。这控制了可以从其他代码访问构造函数的方式。

PrivateConstructor.kt
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
}

这里,主构造函数是私有的,因此必须通过伴生对象中的工厂方法创建实例。 这是一种用于控制对象创建的常见模式,例如在单例实现中。

多个次构造函数

一个类可以有多个次构造函数,每个构造函数都提供了不同的初始化对象的方式。 所有构造函数最终都必须委托给主构造函数。

MultipleConstructors.kt
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 允许为构造函数参数指定默认值,通常不需要次构造函数。 这提供了灵活的初始化选项。

DefaultValues.kt
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
}

默认参数允许使用任意参数组合创建对象。 命名参数使跳过参数时的代码更具可读性。 对于更简单的情况,这种方法通常优于多个构造函数。

构造函数的最佳实践

来源

Kotlin 构造函数文档

本教程深入探讨了 Kotlin 的 constructor 关键字,展示了主构造函数和次构造函数的使用。 我们探讨了各种初始化模式,包括默认值、init 块和可见性修饰符。 正确使用构造函数可以使类设计更易于维护和更灵活。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有多年的编程经验。 自 2007 年以来,我一直在撰写编程文章。 到目前为止,我写了 1400 多篇文章和 8 本电子书。 我有超过八年的编程教学经验。

列出 所有 Kotlin 教程