构造函数是一种初始化类属性的简洁方式。
它是一个特殊的成员函数,在实例化(创建)对象时被调用。但是,它们在 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 对象的 firstName
和 age
属性为 "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 对象时,括号内的参数 fName 和 personAge 分别接受 "Joe"
和 25
的值。但是,fName 和 personAge 在不使用 var
或 val
的情况下使用,并且它们不是 Person
类的属性。
Person
类有两个声明的属性 firstName 和 age。
当创建 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")
}
}
为了区分构造函数参数和属性,使用了不同的名称(fName 和 firstName,以及 personAge 和 age)。使用 _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()
。

在 Kotlin 中,你也可以像 Java 中一样,使用 this()
从同一类的另一个构造函数调用构造函数。
class AuthLog: Log { constructor(data: String): this(data, 10) { // code } constructor(data: String, numberOfData: Int): super(data, numberOfData) { // code } }

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