Kotlin 构造函数

构造函数是一种初始化类属性的简洁方式。

它是一个特殊的成员函数,在实例化(创建)对象时被调用。但是,它们在 Kotlin 中的工作方式略有不同。

在 Kotlin 中,有两种构造函数

  • 主构造函数 - 初始化类的简洁方式
  • 次构造函数 - 允许你添加额外的初始化逻辑

主构造函数

主构造函数是类头的一部分。下面是一个例子

class Person(val firstName: String, var age: Int) {
    // class body
}

被括号包围的代码块是主构造函数:(val firstName: String, var age: Int)

该构造函数声明了两个属性:firstName(只读属性,因为它使用关键字 val 声明)和 age(读写属性,因为它使用关键字 var 声明)。


示例:主构造函数

fun main(args: Array<String>) {

    val person1 = Person("Joe", 25)

    println("First Name = ${person1.firstName}")
    println("Age = ${person1.age}")
}

class Person(val firstName: String, var age: Int) {

}

运行程序后,输出将是

First Name = Joe
Age = 25

当创建 Person 类对象时,将 "Joe"25 这两个值传递给它,就像 Person 是一个函数一样。

这将分别初始化 person1 对象的 firstNameage 属性为 "Joe"25


还有其他使用主构造函数的方法。


主构造函数和初始化器块

主构造函数具有受限的语法,不能包含任何代码。

为了放置初始化代码(不仅仅是初始化属性的代码),使用了初始化器块。它以 init 关键字作为前缀。让我们用初始化器块修改上面的例子

fun main(args: Array<String>) {
    val person1 = Person("joe", 25)
}

class Person(fName: String, personAge: Int) {
    val firstName: String
    var age: Int

    // initializer block
    init {
        firstName = fName.capitalize()
        age = personAge

        println("First Name = $firstName")
        println("Age = $age")
    }
}

运行程序后,输出将是

First Name = Joe
Age = 25

在此,当创建 person1 对象时,括号内的参数 fNamepersonAge 分别接受 "Joe"25 的值。但是,fNamepersonAge 在不使用 varval 的情况下使用,并且它们不是 Person 类的属性。

Person 类有两个声明的属性 firstNameage

当创建 person1 对象时,执行初始化器块内的代码。初始化器块不仅初始化其属性,还打印它们。


这里是执行相同任务的另一种方法

fun main(args: Array<String>) {
    val person1 = Person("joe", 25)
}

class Person(fName: String, personAge: Int) {
    val firstName = fName.capitalize()
    var age = personAge

    // initializer block
    init {
        println("First Name = $firstName")
        println("Age = $age")
    }
}

为了区分构造函数参数和属性,使用了不同的名称(fNamefirstName,以及 personAgeage)。使用 _firstName_age 来代替构造函数参数使用完全不同的名称更为常见。例如

class Person(_firstName: String, _age: Int) {
    val firstName = _firstName.capitalize()
    var age = _age

    // initializer block
    init {
        ... .. ...
    }
}

主构造函数中的默认值

你可以为构造函数参数提供默认值(类似于为函数提供 默认参数和命名参数)。例如

fun main(args: Array<String>) {

    println("person1 is instantiated")
    val person1 = Person("joe", 25)

    println("person2 is instantiated")
    val person2 = Person("Jack")

    println("person3 is instantiated")
    val person3 = Person()
}

class Person(_firstName: String = "UNKNOWN", _age: Int = 0) {
    val firstName = _firstName.capitalize()
    var age = _age

    // initializer block
    init {
        println("First Name = $firstName")
        println("Age = $age\n")
    }
}

运行程序后,输出将是

First Name = Joe
Age = 25

person2 is instantiated
First Name = Jack
Age = 0

person3 is instantiated
First Name = UNKNOWN
Age = 0

Kotlin 次构造函数

在 Kotlin 中,一个类还可以包含一个或多个次构造函数。它们使用 constructor 关键字创建。

次构造函数在 Kotlin 中并不常见。次构造函数最常见的用途是当你需要扩展一个提供多个构造函数以不同方式初始化类的类时。在学习它之前,请务必查看 Kotlin 继承

以下是如何在 Kotlin 中创建次构造函数

class Log {
    constructor(data: String) {
        // some code
    }
    constructor(data: String, numberOfData: Int) {
        // some code
    }
}

在这里,Log 类有两个次构造函数,但没有主构造函数。

你可以像这样扩展类

class Log {
    constructor(data: String) {
        // code
    }
    constructor(data: String, numberOfData: Int) {
        // code
    }
}

class AuthLog: Log {
    constructor(data: String): super(data) {
        // code
    }
    constructor(data: String, numberOfData: Int): super(data, numberOfData) {
        // code
    }
}

在这里,派生类 AuthLog 的构造函数调用基类 Log 的相应构造函数。为此,使用了 super()

Calling constructor of base class from derived class.

在 Kotlin 中,你也可以像 Java 中一样,使用 this() 从同一类的另一个构造函数调用构造函数。

class AuthLog: Log {
    constructor(data: String): this(data, 10) {
        // code
    }
    constructor(data: String, numberOfData: Int): super(data, numberOfData) {
        // code
    }
}
Calling constructor from the same class

示例:Kotlin 次构造函数

fun main(args: Array<String>) {

    val p1 = AuthLog("Bad Password")
}

open class Log {
    var data: String = ""
    var numberOfData = 0
    constructor(_data: String) {

    }
    constructor(_data: String, _numberOfData: Int) {
        data = _data
        numberOfData = _numberOfData
        println("$data: $numberOfData times")
    }
}

class AuthLog: Log {
    constructor(_data: String): this("From AuthLog -> " + _data, 10) {
    }

    constructor(_data: String, _numberOfData: Int): super(_data, _numberOfData) {
    }
}

运行程序后,输出将是

From AuthLog -> Bad Password: 10 times

注意: 如果类没有主构造函数,则次构造函数必须初始化基类或委托给另一个构造函数(如上例所示)。

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战